Linux Socket编程注意事项
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编程注意事项的更多相关文章
- Linux Socket 编程简介
在 TCP/IP 协议中,"IP地址 + TCP或UDP端口号" 可以唯一标识网络通讯中的一个进程,"IP地址+端口号" 就称为 socket.本文以一个简单的 ...
- Linux socket 编程中存在的五个隐患
前言: Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是 开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示如何避免它 ...
- Linux Socket编程
“一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...
- Linux Socket编程(不限Linux)【转】
转自:http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几 ...
- Linux Socket编程(不限Linux)
"一切皆Socket!" 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. --有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信 ...
- Socket详解-Linux Socket编程(不限Linux)
“一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...
- Windows Socket和Linux Socket编程的区别 ZZ
socket相关程序从Windows移植到Linux下需要注意的: 1)头文件 Windows下winsock.h/winsock2.h Linux下sys/socket.h 错误处理:errno.h ...
- Linux socket编程示例(最简单的TCP和UDP两个例子)
一.socket编程 网络功能是Uinux/Linux的一个重要特点,有着悠久的历史,因此有一个非常固定的编程套路. 基于TCP的网络编程: 基于连接, 在交互过程中, 服务器和客户端要保持连接, 不 ...
- Linux Socket编程-(转自吴秦(Tyler))
"一切皆Socket!" 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. --有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信 ...
随机推荐
- 文本导出到pdf文件(使用QPrinter和QPainter和QTextDocument)
程序中数据导出是经常有的需求,今天学习把文本导出到pdf文件.主要是用QPrinter,QPainter TextEditToPdf::TextEditToPdf(QWidget *parent, Q ...
- 基于visual Studio2013解决C语言竞赛题之0907删除记录
题目
- 道格拉斯—普克(Douglas一Peukcer)节点抽稀算法
Douglas一Peukcer算法由D.Douglas和T.Peueker于1973年提出,简称D一P算法,是眼下公认的线状要素化简经典算法.现有的线化简算法中,有相当一部分都是在该算法基础上进行改进 ...
- hibernate笔记(一)
一.主配置文件hibernate.cfg.xml 位置:放在src目录下. 主要包含信息: 一.数据库信息 数据库方言(类的全名) 及 数据库链接信息 1. 数据库方言 2. ...
- RAC 11.2.0.4 安装 遇到 INS-06001
今天安装11.2.0.4的grid软件,在配置passwordless SSH的时候,点击setup 出现此错误 开始网上搜了一把.说什么的都有,什么系统bug啊什么的 但是我另外一套rac却很正常就 ...
- CIconListBox带图标的列表框类
有时候,我们需要在列表框ListBox中插入带图标的文字项,这就需要自己派生一个类出来了,网上的一个CIconListBox类还不错,网站http://www.codeguru.com/Cpp/con ...
- iOS 获取当前时间以及计算年龄(时间差)
获取当前时间 NSDate *now = [NSDate date]; NSLog(@"now date is: %@", now); NSCalendar *calendar = ...
- h和.cpp文件的区别
关于头文件和源文件的分别 首先,我们可以将所有东西都放在一个.cpp文件内. 然后编译器就将这个.cpp编译成.obj,obj是什么东西? 就是编译单元了.一个程序,可以由一个编译单元组成, 也可以有 ...
- 水平线、垂直线——axure线框图部件库介绍
1. 将水平线.垂直线拖动到axure页面编辑区域,如图: 2. 水平线.垂直线相关属性设置 主要属性有.线条的颜色.粗细.线条的样式.箭头的样式 来自:非原型不设计
- 基于visual Studio2013解决面试题之0603调整数组
题目