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接收缓冲区大小的方法来解决

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算法来解决,示例代码如下:

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的情况,示例代码如下:

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的情况,示例代码如下:

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的情况,示例代码如下:

int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int enable = 1; //开启TCP Keepalive机制
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&enable, sizeof(enable));

相关推荐

  1. TCP发送优化ZeroWindow分析

    2024-01-21 13:04:01       53 阅读
  2. TCP发送和接受数据

    2024-01-21 13:04:01       60 阅读
  3. TCP粘包问题优化

    2024-01-21 13:04:01       43 阅读
  4. 发送TCP reset (RST) 包打断TCP连接

    2024-01-21 13:04:01       29 阅读
  5. TCP客户端发送结构体数据

    2024-01-21 13:04:01       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-21 13:04:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-21 13:04:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-21 13:04:01       87 阅读
  4. Python语言-面向对象

    2024-01-21 13:04:01       96 阅读

热门阅读

  1. 李沐深度学习-d2lzh_pytorch模块实现

    2024-01-21 13:04:01       45 阅读
  2. 03 OSPF

    2024-01-21 13:04:01       49 阅读
  3. R语言实现文献计量分析(1)——bibliometrix

    2024-01-21 13:04:01       62 阅读
  4. js变量提升

    2024-01-21 13:04:01       51 阅读
  5. 低代码开发:数据处理与可视化

    2024-01-21 13:04:01       60 阅读
  6. VUE v-if 和 v-show 区别和例子

    2024-01-21 13:04:01       46 阅读