Socket API 是网络应用程序开发中实际应用的标准 API。虽然该 API 简单。可是开发新手可能会经历一些常见的问题。本文识别一些最常见的隐患并向您显示怎样避免它们。

隐患 1.忽略返回状态

第一个隐患非常明显,但它是开发新手最easy犯的一个错误。

假设您忽略函数的返回状态,当它们失败或部分成功的时候,您或许会迷失。

反过来。这可能传播错误。使定位问题的源头变得困难。

捕获并检查每个返回状态。而不是忽略它们。考虑清单 1 显示的样例,一个套接字 send 函数。

清单 1. 忽略 API 函数返回状态

int status, sock, mode;
/* Create a new stream (TCP) socket */
sock = socket( AF_INET, SOCK_STREAM, 0 );
...
status = send( sock, buffer, buflen, MSG_DONTWAIT );
if (status == -1) {
/* send failed */
printf( "send failed: %s\n", strerror(errno) );
} else {
/* send succeeded -- or did it? */
}

清单 1 探究一个函数片断,它完毕套接字 send 操作(通过套接字发送数据)。函数的错误状态被捕获并測试,但这个样例忽略了 send 在无堵塞模式(由 MSG_DONTWAIT 标志启用)下的一个特性。

send API 函数有三类可能的返回值:

· 假设数据成功地排到传输队列。则返回 0。

· 假设排队失败。则返回 -1(通过使用 errno 变量能够了解失败的原因)。

· 假设不是全部的字符都可以在函数调用时排队,则终于的返回值是发送的字符数。

因为 send 的 MSG_DONTWAIT 变量的无堵塞性质,函数调用在发送全然部的数据、一些数据或没有发送不论什么数据后返回。在这里忽略返回状态将导致不全然的发送和随后的数据丢失。

隐患 2.对等套接字闭包

UNIX 有趣的一面是您差点儿能够把不论什么东西看成是一个文件。文件本身、文件夹、管道、设备和套接字都被当作文件。

这是新颖的抽象,意味着一整套的 API 能够用在广泛的设备类型上。

考虑 read API 函数,它从文件读取一定数量的字节。

read 函数返回读取的字节数(最高为您指定的最大值);或者 -1,表示错误;或者 0,假设已经到达文件末尾。

假设在一个套接字上完毕一个 read 操作并得到一个为 0 的返回值,这表明远程套接字端的对等层调用了 close API 方法。该指示与文件读取同样 —— 没有多余的数据能够通过描写叙述符读取(參见 清单 2)。

清单 2.适当处理 read API 函数的返回值

int sock, status;
sock = socket( AF_INET, SOCK_STREAM, 0 );
...
status = read( sock, buffer, buflen );
if (status > 0) {
/* Data read from the socket */
} else if (status == -1) {
/* Error, check errno, take action... */
} else if (status == 0) {
/* Peer closed the socket, finish the close */
close( sock );
/* Further processing... */
}

相同,能够用 write API 函数来探測对等套接字的闭包。

在这样的情况下,接收 SIGPIPE 信号,或假设该信号堵塞,write 函数将返回 -1 并设置 errno 为 EPIPE。

隐患 3.地址使用错误(EADDRINUSE)

您能够使用 bind API 函数来绑定一个地址(一个接口和一个port)到一个套接字端点。能够在server设置中使用这个函数,以便限制可能有连接到来的接口。也能够在client设置中使用这个函数,以便限制应当供出去的连接所使用的接口。bind 最常见的使用方法是关联port号和server,并使用通配符地址(INADDR_ANY),它同意不论什么接口为到来的连接所使用。

bind 普遍遭遇的问题是试图绑定一个已经在使用的port。

该陷阱是或许没有活动的套接字存在,但仍然禁止绑定port(bind 返回EADDRINUSE)。它由 TCP 套接字状态 TIME_WAIT 引起。该状态在套接字关闭后约保留 2 到 4 分钟。

在 TIME_WAIT 状态退出之后。套接字被删除,该地址才干被又一次绑定而不出问题。

等待 TIME_WAIT 结束可能是令人恼火的一件事,特别是假设您正在开发一个套接字server,就须要停止server来做一些修改,然后重新启动。幸运的是,有方法能够避开 TIME_WAIT 状态。能够给套接字应用 SO_REUSEADDR 套接字选项,以便port能够立即重用。

考虑清单 3 的样例。在绑定地址之前,我以 SO_REUSEADDR 选项调用 setsockopt。

为了同意地址重用,我设置整型參数(on)为 1 (不然。能够设为 0 来禁止地址重用)。

清单 3.使用 SO_REUSEADDR 套接字选项避免地址使用错误

int sock, ret, on;
struct sockaddr_in servaddr;
/* Create a new stream (TCP) socket */
sock = socket( AF_INET, SOCK_STREAM, 0 ):
/* Enable address reuse */on = 1;
ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
/* Allow connections to port 8080 from any available interface */
memset( &servaddr, 0, sizeof(servaddr) );servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
servaddr.sin_port = htons( 45000 );
/* Bind to the address (interface/port) */
ret = bind( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) );

在应用了 SO_REUSEADDR 选项之后,bind API 函数将同意地址的马上重用。

隐患 4.TCP 中的帧同步假定

TCP 不提供帧同步,这使得它对于面向字节流的协议是完美的。这是 TCP 与 UDP(User Datagram Protocol,用户数据报协议)的一个重要差别。UDP 是面向消息的协议,它保留发送者和接收者之间的消息边界。TCP 是一个面向流的协议,它假定正在通信的数据是无结构的,如图 1 所看到的。

图 1.UDP 的帧同步能力和缺乏帧同步的 TCP

图 1 的上部说明一个 UDP client和server。左边的对等层完毕两个套接字的写操作,每一个 100 字节。

协议栈的 UDP 层追踪写的数量,并确保当右边的接收者通过套接字获取数据时,它以相同数量的字节到达。换句话说。为读者保留了写者提供的消息边界。

如今,看图 1 的底部.它为 TCP 层演示了同样粒度的写操作。两个独立的写操作(每一个 100 字节)写入流套接字。

但在本例中,流套接字的读者得到的是 200 字节。协议栈的 TCP 层聚合了两次写操作。这样的聚合能够发生在 TCP/IP 协议栈的发送者或接收者中不论什么一方。

重要的是,要注意到聚合或许不会发生 —— TCP 仅仅保证数据的有序发送。

对大多数开发者来说,该陷阱会引起困惑。

您想要获得 TCP 的可靠性和 UDP 的帧同步。除非改用其它的传输协议,比方流传输控制协议(STCP),否则就要求应用层开发者来实现缓冲和分段功能。

Linux Socket编程注意事项的更多相关文章

  1. Linux Socket 编程简介

    在 TCP/IP 协议中,"IP地址 + TCP或UDP端口号" 可以唯一标识网络通讯中的一个进程,"IP地址+端口号" 就称为 socket.本文以一个简单的 ...

  2. Linux socket 编程中存在的五个隐患

    前言:         Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是   开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示如何避免它 ...

  3. Linux Socket编程

    “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...

  4. Linux Socket编程(不限Linux)【转】

    转自:http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几 ...

  5. Linux Socket编程(不限Linux)

    "一切皆Socket!" 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. --有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信 ...

  6. Socket详解-Linux Socket编程(不限Linux)

    “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...

  7. Windows Socket和Linux Socket编程的区别 ZZ

    socket相关程序从Windows移植到Linux下需要注意的: 1)头文件 Windows下winsock.h/winsock2.h Linux下sys/socket.h 错误处理:errno.h ...

  8. Linux socket编程示例(最简单的TCP和UDP两个例子)

    一.socket编程 网络功能是Uinux/Linux的一个重要特点,有着悠久的历史,因此有一个非常固定的编程套路. 基于TCP的网络编程: 基于连接, 在交互过程中, 服务器和客户端要保持连接, 不 ...

  9. Linux Socket编程-(转自吴秦(Tyler))

    "一切皆Socket!" 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. --有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信 ...

随机推荐

  1. 在Windows下用Eclipse+CDT+MinGW搭建C++开发平台

    本文提供了在Windows下用Eclipse+CDT+MinGW搭建C / C++开发平台的方法, 测试平台为Windows XP Sp2 CHS.   以下软件均为Windows平台下的版本. 1. ...

  2. 统一横轴墨卡托投影(UTM)

    UTM 坐标系统使用基于网格的方法表示坐标.UTM 系统将地球分为 60 个区,每一个区基于横轴墨卡托投影.画图法中的地图投影方法能够在平面中表示一个两维的曲面,比如一个标准地图.图 1 展示了一个横 ...

  3. AdapterView<?> arg0, View arg1, int arg2, long arg3參数含义

    arg0:是指父Vjew arg1就是你点击的那个Item的View arg2是position,position是你适配器里面的position arg3是id,通常是第几个项.id是哪个项View ...

  4. 浅谈初次搭建nginx+php+mysql遇到的问题

    先说明下我linux上的环境: nginx + php(5.5.10) + mysql 開始的源代码已经在本地写好,并调试成功(本地的环境是用XAMPP的默认配置).在把代码上传至linux上时,出现 ...

  5. 【linux】arm mm内存管理

    欢迎转载,转载时请保留作者信息,谢谢. 邮箱:tangzhongp@163.com 博客园地址:http://www.cnblogs.com/embedded-tzp Csdn博客地址:http:// ...

  6. Python中使用Flask、MongoDB搭建简易图片服务器

    主要介绍了Python中使用Flask.MongoDB搭建简易图片服务器,本文是一个详细完整的教程,需要的朋友可以参考下 1.前期准备 通过 pip 或 easy_install 安装了 pymong ...

  7. poj-3895-Cycles of Lanes 简单DFS

    题目链接: http://poj.org/problem?id=3895 题目意思: 在无向连通图中图中找一个经过边数最多的环. 解题思路: 从任意一点直接DFS,不用回溯,注意构成环的话至少有3条边 ...

  8. EasyUI - Messager消息框

    全局设定: JavaScript代码: //设置按钮中的文字,默认是-ok/cancel ,可以任意设置文字,比如现在的-确认/取消 $.messager.defaults = { ok: '确认', ...

  9. ASP.NET - 出错页

    配置Web.config,配置customError区域. <system.web> <customErrors mode ="RemoteOnly" defau ...

  10. 细节!重点!易错点!--面试java基础篇(一)

    今天来给大家分享一下java的重点易错点部分,也是各位同学面试需要准备的,欢迎大家交流指正. 1.java中的main方法是静态方法,即方法中的代码是存储在静态存储区的. 2.任何静态代码块都会在ma ...