TCP/IP网络编程 -- (九)套接字的多种可选项

TCP/IP网络编程 -- (九)套接字的多种可选项

之前写的程序都是创建好 socket 后未经特殊设置直接使用,但有时需要更改

image

getsockopt & setsocket

可以对上述的可选项进行读取和设置操作(有些只能进行一种操作)

读取和设置根据以下两个函数完成

#include <sys/socket.h>
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

sock:用于查看 socket 的文件描述符

level:要查看的可选项的协议层

optname:要查看的可选项名

optval:保存查看结果的缓冲地址值

optlen:保存 optval 的字节数

#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

参数与上述相同

state = getsocket(tcp_sock, SOL_SOCKET, SO_TYPE, (void*)&sock_type, &optlen);

运行后 sock_type = 1,因为 SOCK_STREAM 的类型常数为 1

SO_SNDBUF & SO_RCVBUF

用于调整输出缓存与输入缓存的大小

读取 I/O 缓冲大小

state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);

设置 I/O 缓存

int rcv_buf = 1024 * 3;
state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, sizeof(rcv_buf));

Time-wait 状态

在第五章实现的 echo_server.c 与 echo_client.c 中,如果在 client 输入 Q 或者 ctrl + C 终止程序,那么 client 会向 server 发送 fin 来开始四次挥手过程,这种情况是没有问题的

但是如果在 server 端首先 ctrl + C 关闭连接,再次在同一端口启动 server 时会出现 "bind() error",等待三分钟后在同一端口启动可以正常运行

这是因为 TCP 四次挥手的过程中,主动断开连接的一方 A 会有一个 Time-wait 状态,是为了防止 A 发送的最后一次挥手对方没有收到,B 重传了 fin,而这时连接已经中断了

image

但是如果客户端首先发起断开请求则不会出现该情况,因为客户端不是指定端口号而是自动分配,不会短时间内重复分配相同端口

地址再分配

Time-wait 也有缺点,如果系统发生故障紧急停止,下次重连时还要等待几分钟,甚至在第四次挥手丢失时还会重启 Time-wait,时间会更长

image

解决方案是在 socket 可选项中更改 SO_REUSEADDR 状态,如果 SO_REUSEADDR 设为 1 则表示新的 socket 可以使用正在 Time-wait 阶段的端口号,为 0 则不可使用(默认情况)

optlen = sizeof(option);
option = true;
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen);

9.3TCP_NODELAY

Nagle 算法

为了防止网络中的数据包太多发生网络过载,发明了 Nagle 算法,如果设包含很少有效载荷的数据包为小包,载荷大小为一个 MSS 的是大包,核心是

网络中的数据包尽可能以大包的形式发送

image

只有收到前一个数据的 ACK 时,Nagle 算法才发送下一个数据,但是已经先进入到输出缓冲中

但不是什么情况下使用 Nagle 都更好,如果传输大文件时不使用 Nagle 会更好,因为即使不使用,网络中大部分也是大包,反而无需等待 ACK 就可流水线地发送数据包

禁用 Nagle 算法

将 TCP_NODELAY 改为 1 即可

int opt_val = 1;
setsocket(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, sizeof(opt_val));
posted @ 2023-03-15 19:54  hzy0227  阅读(33)  评论(0编辑  收藏  举报