本章所有示例代码>>github
套接字具有多种特性,这些特性可通过可选项更改。
9.1 套接字可选项和I/O缓冲
1. 套接字的多种可选项
由上表看出,套接字可选项是分层的。IPPROTO_IP层可选项是IP协议相关事项,IPPROTO_TCP层可选项是TCP协议相关的事项,SOL_SOCKET层是套接字相关的通用可选项。
2. getsockopt& setsockopt
可选项的读取(Get)和设置(Set)通过如下两个函数完成。
#include <sys/socket.h>
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
-sock: 用于查看选项套接字文件描述符;
-level: 要查看的可选项的协议层;
-optname: 要查看的可选项名;
-optval: 保存查看结果的缓冲地址值;
-optlen: 第四个参数optval传递的缓冲大小。调用函数后,该变量中保存
通过第四个参数返回的可选项信息的字节数;
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void*optval, socklen_t optlen);
3. SO_SNDBUF& SO_RCVBUF
SO_RCVBUF是输入缓冲大小相关可选项,SO_SNDBUF是输出缓冲大小相关可选项。用这2个可选项可以读取当前I/O缓冲大小,也可以进行更改。
缓冲大小的设置需谨慎处理,系统不会完全按照该函数进行设置,只是通过调用setsockopt函数向系统传递要求的缓冲大小值。
9.2 SO_REUSEADDR
1. 发生地址分配错误(Bind Error)
服务器端向客户端发生FIN消息(服务器端请求断开连接),如果以这种方式终止程序,那服务器端重新运行时将产生问题。如果用同一端口号重新运行服务器端,会产生“bind()error”错误,并且无法再次运行,等待大约3分钟后才能重新运行服务器端。
2. Time-wait状态
只有先断开连接(先发送FIN消息)的主机才经过Time-wait状态,因此,若服务器端先断开连接,则无法重新运行。套接字处在Time-wait状态时,端口正在使用,所以bind错误。
由于客户端套接字的端口号是任意指定的,客户端每次运行时都会动态分配端口号,所以无需过多关注Time-wait状态。
考虑SEQ 5001、ACK 7502这条消息在传递途中丢失,未能传给主机B,这时会发生什么?重传,所以主机A套接字应处在Time-wait状态等待。
3. 地址再分配
在套接字的可选项中更改SO_REUSEADDR的状态。
SO_REUSEADDR的默认值为0(FALSE),将这个值改为1(TRUE),即可重新分配Time-wait状态下的端口号。
optlen = sizeof(option);
option = TRUE;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)option,optlen);
9.3 TCP_NODELAY
Nagle算法
为防止因数据包过多而发生网络过载,应用于TCP层。TCP套接字默认使用Nagle算法交换数据,因此最大限度地进行缓冲,直到收到ACK。若不使用Nagle算法,发送过程与ACK接收无关,数据到达缓冲将立即被发送出去,对网络流量(Traffic:指网络负载或混杂程度)产生负面影响。为提高网络传输效率,必须使用Nagle算法。
但Nagle算法并不是什么时候都适用。根据传输数据的特性,网络流量未受太大影响时,不使用Nagle算法要比使用它时传输速度快。(如,传输大文件数据)
一般情况下,不使用Nagle算法可以提高传输速度。但如果无条件放弃使用Nagle算法,就会增加过多的网络流量,反而影响传输。
设置Nagle算法的状态:
int opt_val = 1;
setsockopt(sock,IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, sizeof(opt_val));
查看Nagle算法的状态:
int opt_val;
socklen_t opt_len;
opt_len =sizeof(opt_val);
getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, &opt_len);