int getsockopt(int sockfd, int level, intoptname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, intoptname, const void *optval, socklen_t optlen);
//获取与设置套接字选项的函数
通用套接字选项:
(一)SO_RCVBUF和SO_SNDBUF
每个套接字都有一个发送缓冲区和一个接收缓冲区。对于TCP来说,套接字接收缓冲区中的可用空间的大小限制了TCP通告对端的窗口大小。TCP接收缓冲区不可能溢出,因为如果对端无视窗口限制大小发送超过限制大小的数据,本端TCP将直接丢弃。对于UDP来说,当接收的数据报装不进接收缓冲区时候,该数据就被丢弃:较快的发送端可以很容易的淹没较慢的接收端,导致UDP接收端丢弃数据报(甚至较快的发送端可以淹没本机的网络接口,导致数据报被本机丢弃)
当设置TCP套接字接收缓冲区的大小时,函数调用顺序重要。因为TCP的窗口规模选项是在建立连接时用SYN分节与对端互换得到的。因此, 对于客户,函数必须在connect之前调用; 对于服务器,函数必须在listen之前给监听套接字设置(为什么是设置监听套接字? 因为客户套接字是在三路握手完成后由accept取出,此时设置已再无影响。然而,新创建的套接字属性可以从监听套接字那里继承得到)
当我们用setsockopt设置了TCP的接收缓冲区和发送缓冲区的大小时,系统都会将其值加倍,并且不得小于某个最小值
(二)SO_REUSEADDR和SO_REUSEPORT
SO_REUSEADDR选项能起到以下4个作用:
1、它允许启动一个监听服务器并捆绑其众所周知的端口,即使以前建立的将该端口用作他们的本地端口的连接仍存在(由以下种情况导致)
a)启动一个监听服务器
b)连接请求到达,派生一个子进程来处理这个客户
c)监听服务终止,但子进程仍然为客户服务(此刻服务器进程处于 TIME_WAIT状态,因为其主动关闭连接)
d)重启监听服务器
默认情况下,服务器通过socket、bind和listen重新启动时,由于它试图捆绑一个现有连接(即正由早先派生的那个子进程处理着连接)的端口,bind会失败。但是如果在socket和bind之间调用SO_REUSEADDR选项,那么bind会成功
2