setsockopt 函数可以设置应用层、传输层、网络层的一些属性,比如
- 应用层:绑定地址快速重用、允许广播、
- 传输层:设置TCP最大数据段大小
- 网络层:设置IP首部选项、服务类型、生存时间
目录
1、setsockopt 参数和返回值解析
2、使用setsockopt 函数设置网络属性
(1) 绑定地址快速重用
(2) 允许广播
(3) 设置接收超时时间
1、setsockopt 参数和返回值解析
setsockopt函数设置网络属性,是针对套接字的,因为服务端和客户端的TCP数据段大小、接收缓冲区大小是可以不一样的。
第一个参数 sockfd:你要设置哪个套接字的网络属性
第二个参数 level:你要设置哪一层的网络属性。上面提到,你可以设置应用层、传输层、网络层等三层的网络属性。这三层对应的可选值如下:
可选值 | 含义 |
SOL_SOCKET | 应用层 |
IPPRO_TCP | 传输层 |
IPPROTO_IP | 网络层 |
第三个参数 optname:在选好第二个参数的基础上,要设置该层的哪个属性。
如果第二个参数是 SOL_SOCKET, 可选值如下。因为第三个参数是void* 类型,所以填入的数据类型有多种,其中比较容易混淆的是 int 类型
- 比如 SO_REUSERADDR,这里的int类型相当于一个bool类型,0代表false,1代表true
- 比如 SO_RCVBUF,因为是要设置缓冲区大小,所以这里的int类型就代表要设置的字节数
可选值 | 含义 | 数据类型 |
SO_REUSEADDR | 允许重用本地地址和端口 | int |
SO_BROADCAST | 允许发送广播数据 | int |
SO_RCVTIMEO | 设置接收超时时间 | struct timeval (定义放在表格末尾) |
SO_SNDTIMEO | 设置发送超时时间 | struct timeval (定义放在表格末尾) |
SO_RCVBUF | 接收缓冲区大小 | int |
SO_SNDBUF | 发送缓冲区大小 | int |
SO_RCVLOWAT | 接收缓冲区下限 | int |
SO_SNDLOWAT | 发送缓冲区下限 | int |
SO_KEEPALIVE | 保持连接 | int |
SO_DEBUG | 允许调试 | int |
SO_DONTROUTE | 不查找路由 | int |
SO_LINGER | 延迟关闭连接 | struct linger |
SO_OOBINLINE | 带外数据放入正常数据流 | int |
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
如果第二个参数是 IPPRO_TCP,可选值如下:
可选值 | 含义 | 数据类型 |
TCP_MAXSEG | TCP最大数据段的大小 | int |
TCP_NODELAY | 不使用Nagle算法 | int |
如果第二个参数是 IPPROTO_IP,可选值如下:
可选值 | 含义 | 数据类型 |
IP_HDRINCL | 在数据包中包含IP首部 | int |
IP_OPTIONS | IP首部选项 | int |
IP_TTL | 生存时间 | int |
第四个参数 optlen:第三个参数对应的数据类型所占字节数。如果第三个参数填入的是int 类型,第四个参数就填 sizeof(int)
返回值:成功返回 0,失败返回 -1
2、使用setsockopt 函数设置网络属性
(1) 绑定地址快速重用
我们在运行服务端的时候,如果进程直接中断(比如收到了Ctrl+C发送了进程终止信号),此时没有正常完成四次挥手,服务端会进入close_wait状态,这个状态会持续两分钟左右。
这个时候如果我们重新运行服务端,bind函数会调用失败,因为上一次的服务端尽管处在close_wait状态,但依然在占用IP地址和端口号。为了不让服务端继续占用,我们可以将套接字的网络属性设为重用状态,表示上一个服务端就继续等吧,但是别占用资源。
int b_reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
(2) 允许广播
int b_br = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &b_br, sizeof(int));
(3) 设置接收超时时间
struct timeval tout;
tout.tv_sec = 5;
tout.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(struct timeval));