TCP/IP网络编程 学习笔记_十 -套接字的多种可选项

TCP/IP网络编程 学习笔记_10 --套接字的多种可选项

前言:套接字其实具有多种特性,这些特性是可以通过可选项更改或查看的。我们前面使用套接字只是使用它的默认特性而已。但是在实际网络编程中,我们常常需要根据需求修改默认特性。本章我们就来介绍查看和修改套接字可选项的方法。

  • 套接字多种可选项:套接字可选项是分层的,如:SOL_SOCKET层,IPPROTO_IP层,IPPROTO_TCP层等,每一层都对应有多种特性字段。

  • 查看和修改可选项的函数

    int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
    成功返回0,失败时返回-1

    sock:要查看的套接字文件描述符
    level:要查看的可选项的协议层
    optname:要查看的可选项名
    optval:保存查看结果的缓冲地址值
    optlen:保存查看结果optval返回的字节数

    int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
    成功时返回0,失败返回-1

  • 常见可选项
    1,协议层为SOL_SOCKET下的SO_TYPE可选项,可查看套接字的类型(TCP或UDP).

    2,协议层为SOL_SOCKET下的SO_SNDBUF和SO_RCVBUF可选项,分别是可以设置输出缓冲和输入缓冲的大小。

    3,协议层为SOL_SOCKET下的SO_REUSEADDR可选项,可以设置地址是否可以再分配。下面我们来详细讲讲它的用法:

    首先,我们回想下以前写过的一个回声程序(学习笔记_5),我们做这样一个操作,”先关闭客服端程序,再关闭服务端程序”,然后马上又打开服务端程序,发现一切正常。然而,如果是”先关闭服务端程序,再关闭客服端程序”,再马上打开服务端,你会发现服务端bind()地址会失败。想过这是什么原因吗?
    其实这和TCP断开连接的四次握手有关,谁先发出断开请求(FIN),那么在收到对面回复的断开请求时会启动一个计时器(3分钟左右,确保最后一次握手对方已收到),在计时器启动期间,对应套接字还能接收消息,对应的端口号状态是被占用的,所以如果服务端退出时启动了这个计时器,那么马上再打开,bing()会失败,因为目前端口还被上次占用了,默认不能重新再分配。但是,对于先关闭客服端,就不会有这种问题,不是因为客服端不会产生这样的计时器,它同样会启动计时器,只是因为客服端的端口号每次运行程序时是动态分配的。示意图如下:
    TCP/IP网络编程 学习笔记_十 -套接字的多种可选项

    默认这个计时器是可以开启的,但在有些时候这么做是不合理的,如系统发生故障从而紧急停止的情况,这时需要尽快重启服务器,但因处于计时器等待(Time-wait)期间而必须等几分钟甚至更长。我们可以通过可选项SO_REUSEADDR来修改在Time-wait状态下端口号是否可以重新分配给新套接字。SO_REUSEADDR的默认值为0(假),我们将其修改为1(真),就能解决上面的问题了。
    //加在调用bind()之前
    int option;
    socklen_t optlen;
    optlen = sizeof(option);
    option = TRUE;
    setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &option, optlen);


4,协议层为IPPROTO_TCP下的TCP_NODELAY可选项,可以设置是否禁止Nagle算法。默认是开启的(0),禁用只需将其值改为1(真)即可。

int opt_val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&opt_val, sizeof(opt_val));

那么什么是Nagle算法呢?这个算法主要是为了防止因数据包过多而发生网络过载而设置的。如果开启了这个算法,那么TCP数据交互时,就会一个一个数据包有序的传输,即SEQ与ACK一一对应传输。而如果不使用这个算法,那么个个数据的交互就会是异步进行的,SEQ消息与ACK消息同时发送,不等待上一条。示例图如下:
TCP/IP网络编程 学习笔记_十 -套接字的多种可选项
由图可以看出,他们传递同样的数据(Nagle),使用Nagle算法共只需4个数据包完成传输,但不使用Nagle算法则需要共传输10个数据包(这只是一个示例图,实际不一定是这么多次,只是为了说明这个原理)。所以不使用Nagle算法会产生更多的流量,即使只传输1个字节数据,但一个数据包的头信息都有可能是几十个字节。因此,一般我们默认是需要使用Nagle算法的。
然而,在有些时候使用它并不合理,因为不使用Nagle算法,它可以无需等待ACK的前提下连续传输,在网络流量未受太大影响时,不使用Nagle算法比使用它时传输速度快。最典型的就是传输大文件数据时,因文件数据传输到缓冲比较快,即便不使用Nagle算法,也会在装满输出缓冲时传输数据包,不会增加多少数据包。

版权声明:本文为博主原创文章,未经博主允许不得转载。