接口原型:
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
成功时返回0,失败时返回-1,并设置errno。
参数解释:
sockdf参数表示要操作的套接字;level参数表示要接口影响的范围,如果为SOL_SOCKET表示操作套接字本身,为IPPRO_IP、IPPROTO_TCP则表示要影响的是该进程下该协议的所有套接字;optname选项表示要设置什么功能;optval表示该功能的选项是什么(比如为1就开启,为0就关闭,或者是一个结构体用来指定复杂选项),optlen表示选项参数的长度(因为可能是个结构体,所有需要知道长度)。
以设置套接字允许重用地址和端口为例:
int sock = socket(AF_INET, SOCK_STREAM, 0);
int opt=1;
setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
这样就可以让sock套接字bind与其他套接字相同的IP地址和端口,前提是其他套接字也设置了这个选项。
用来解决的实际问题例1:
在编写网络计算器练习时发现,当客户端向服务器connect后,并且服务器进行了accept,此时如果服务器进程突然被中止,则
- 服务器进程被中止后,它的所有打开的套接字描述符都会被关闭,这会导致服务器向客户端发送一个FIN,表示关闭连接。客户端收到FIN后,会回复一个ACK,并进入CLOSE_WAIT状态,等待客户端关闭连接。
- 客户端如果此时没有数据要发送,而是阻塞在读取用户输入或者接收服务器数据的操作上,那么它不会立即关闭连接,而是继续等待。这样,客户端和服务器的连接就处于半关闭的状态,即客户端到服务器的通道已经关闭,而服务器到客户端的通道还没有关闭。在这个CLOSE_WAIT状态中,原本的套接字绑定的IP地址和端口还没有被真正释放。
- 此时如果重新运行服务器进程,并绑定相同的端口则会引发Bind failed错误。
设置sock套接字可以重用地址和端口后,即可保证服务器可以立即重启,不触发Bind failed错误。
附level与optname的常用选项:
- 在SOL_SOCKET层,常用的选项有:
- SO_REUSEADDR:允许重用本地地址和端口。
- SO_BROADCAST:允许发送广播数据。
- SO_KEEPALIVE:启用TCP保活机制。
- SO_RCVBUF和SO_SNDBUF:设置接收和发送缓冲区的大小。
- SO_RCVTIMEO和SO_SNDTIMEO:设置接收和发送超时时间。
- SO_LINGER:延迟关闭连接。
- 在IPPROTO_IP层,常用的选项有:
- IP_HDRINCL:在数据包中包含IP首部。
- IP_OPTIONS:设置IP首部选项。
- IP_TTL:设置生存时间(TTL)。
- 在IPPROTO_TCP层,常用的选项有:
- TCP_MAXSEG:设置TCP最大数据段的大小。
- TCP_NODELAY:禁用Nagle算法,即不对小数据包进行缓存合并。