TCP发送优化(ZeroWindow分析)

通信模型一:

Client 创建一个 TCP 的 socket,并通过 SO_SNDBUF 选项设置它的发送缓冲区大小为 2048Byte,连接到 Server 后,每 1 秒发送一个 TCP报文(1024Byte)。Server 端不调用 recv()。预期的结果则分为以下几个阶段:

阶段1:Server 端的 socket 接收缓冲区未满,所以尽管 Server 不会 recv(),但依然能对 Client 发出的报文回复 ACK;

阶段2: Server 端的 socket 接收缓冲区被填满了,向 Client 端通告零窗口(Zero Window)。Client 端待发送的数据开始累积在 socket 的发送缓冲区;

阶段3: Client 端的 socket 的发送缓冲区满了,用户进程阻塞在 send函数里。

实际执行时,表现出来的现象也"基本"符合预期。不过当我们在 Client 端通过 netstat -an 监控 TCP 连接的发送队列长度时,发现这个值竟然从 0 最终增长到 14480,它轻松地超了之前设置的 SO_SNDBUF 值(2048)

分析

以上就是一个简单的Zero Window产生的模型,简单来说,Zero Window问题就是指在TCP连接中,发送方为了保障可靠传输,会根据接收方反馈的窗口大小来控制发送窗口的大小,但当接收方窗口大小为0时,发送方就会停止发送,从而导致通讯阻断的问题。所以起解决办法有以下几种。

一、增加接收方窗口大小

一种常用的方法是增加接收方的窗口大小。这样可以使得接收方有更多的缓存空间,从而避免出现Zero Window的情况。可以通过修改TCP接收缓冲区大小的方法来解决

bash 复制代码
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int buf_size = 1024 * 1024 * 5; //设置缓存区大小为5MB
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size));

二、禁用Nagle算法(默认是打开的)

Nagle算法是一种优化TCP传输的算法,其原理是将小的数据包合并成一个大的数据包再发送,从而减少网络传输量。但是当数据量很小的时候,会导致数据包积压,造成Zero Window问题。可以通过禁用Nagle算法来解决,示例代码如下:

bash 复制代码
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int enable = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable));

三、增加发送方的等待时间

在一些情况下,由于网络状况不良,导致接收方没有足够的时间处理数据,造成Zero Window的情况。可以通过增加发送方的等待时间,等待接收方处理完成后再发送数据,从而避免出现Zero Window的情况,示例代码如下:

c 复制代码
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct timeval timeout;
timeout.tv_sec = 0; 
timeout.tv_usec = 500*1000; //等500毫秒
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));

四、增加发送方的重传次数

在一些情况下,由于网络状况不良或者其他原因,导致数据丢失或者接收方无法正确接收数据,造成Zero Window的情况。可以通过增加发送方的重传次数,保证数据能够正确传输,从而避免出现Zero Window的情况,示例代码如下:

c 复制代码
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int retry_count = 6; //最多重试6次
setsockopt(sock, SOL_TCP, TCP_SYNCNT, (void*)&retry_count, sizeof(retry_count));

五、使用TCP Keepalive机制

TCP Keepalive机制是一种保持TCP连接的机制,其原理是在TCP连接空闲一段时间后,会向对端发送心跳包,以检测连接是否还存活。可以通过使用TCP Keepalive机制来避免出现Zero Window的情况,示例代码如下:

c 复制代码
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int enable = 1; //开启TCP Keepalive机制
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&enable, sizeof(enable));
相关推荐
BD_Marathon1 小时前
【JavaWeb】HTTP_请求和响应的报文格式
网络·网络协议·http
骥龙8 小时前
3.10、构建网络防线:防火墙、WAF 与蜜罐实战
服务器·网络·数据库·网络安全
国科安芯9 小时前
国产RISC-V架构MCU在工控系统中的节能性分析
网络·单片机·嵌入式硬件·fpga开发·性能优化·架构·risc-v
云宏信息9 小时前
运维效率提升实战:如何用轻量化云管平台统一纳管与自动化日常资源操作
运维·服务器·网络·架构·云计算
TG:@yunlaoda360 云老大11 小时前
如何了解腾讯云国际站代理商FL有什么跨境优势呢?
网络·云计算·腾讯云
飞Link12 小时前
GDN:深度学习时代的图偏差网络异常检测全解析
网络·人工智能·深度学习
破刺不会编程13 小时前
socket编程TCP
linux·运维·服务器·开发语言·网络·网络协议·tcp/ip
gxh199213 小时前
4步将HTTP请求升级为HTTPS
运维·服务器·网络协议·http·https
BullSmall13 小时前
日志打印IP:安全与合规的最佳实践
网络·tcp/ip·安全
易天ETU15 小时前
短距离光模块 COB 封装与同轴工艺的区别有哪些
网络·人工智能·光模块·光通信·cob·qsfp28·100g