TCP 糊涂窗口综合症(silly window syndrome)与 rate-based 流控-CSDN博客

昨天同事给我看了一个有趣的 case,接收端抓包:
在这里插入图片描述
现象就是这样,但结论也很明显:

  • ack 渐长,win 渐缩,有数据陆续到达 rcvbuff,但 app 尚未读取。
  • ack 不变,win 渐长,没有新数据到达,app 持续读取数据。

据说这是个 iOS 系统的 case。

该现象与 Linux TCP 并不匹配,Linux TCP 仅在下面的情况才会发送 win update:

  • 窗口从 0 变为非 0,且…
  • rwnd 腾出了一半的空间。

条件过于苛刻。做以下实验:

Linux server 端代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

#define SIZE 16384
#define PORT 1234

void senddata(int csd)
{
    char buff[SIZE];
    int n, i;
    for (i = 0; i < 8; i++) {
        write(csd, buff, sizeof(buff));
    }
    getchar();
}

int main()
{
    int sockfd, csd, len;
    struct sockaddr_in servaddr, cli;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    listen(sockfd, 5);
    len = sizeof(cli);

    while(1) {
        csd = accept(sockfd, (struct sockaddr *)&cli, &len);
        senddata(csd);
        close(csd);
    }
}

Linux client 和 MacOS client 端代码:

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

#define SIZE 2048
#define PORT 1234

void recvdata(int sd)
{
    char buff[SIZE];
    int n, i;
    getchar();
    for (i = 0; i < 64; i++) {
        read(sd, buff, sizeof(buff));
    }
}

int main()
{
    int sd, connfd;
    struct sockaddr_in servaddr, cli;

    sd = socket(AF_INET, SOCK_STREAM, 0);

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("192.168.10.6");
    servaddr.sin_port = htons(PORT);
    connect(sd, (struct sockaddr*)&servaddr, sizeof(servaddr));
    recvdata(sd);
    close(sd);
}

运行 client 后敲回车,结果显示,MacOS client 在敲下会车后从 rcvbuff 读取了一定字节后就会发送 win update,而 Linux 不会。

OK,开始评谈。

早期,资源所限,为避免糊涂窗口综合症,TCP 采取一定措施规避,但在事情的反面反而阻碍了 rate-based 流控。

糊涂窗口综合症本质上包括下面因素:

  • 接收端接收数据太慢。
  • 发送端产生数据太慢。
  • 担心网络上充斥小包。

但根据管道模型,理论上哪怕一次通告 1 字节 rwnd,只要通告速度足够快,依然可达任意带宽。问题是:

  • 如果接收端接收速度足够快,窗口还糊涂吗?
  • 既然接收端慢可以影响发送,为什么接收端快就不能呢?

如何从面向 rcvbuff 的流控转向面向应用程序接收能力的 rate-based 流控,问题就在于何时发送 win update。Linux TCP 在应用程序读取数据后发送 win update 的条件太苛刻。

如今早年的限制已不再:

  • 内存足够大,可承受更大的意外突发。
  • 带宽足够大,可容忍长报头损失的载荷率。
  • 拥塞控制纷纷从 buffer-based 转向 rate-based。

Linux TCP 在 30 年后依然是很吝啬的实现,旨在节省资源以适应早期环境,MacOS 似乎好一点,但我还没 deep into Darwin 代码,不评说。

糊涂窗口综合症是慢速环境下的症状,减缓症状的措施在高速环境下必然掣肘。

看看 win update after read 的益处:
在这里插入图片描述

皮鞋不会胖
蜷缩着过活,总希望是大梦一场,
可我挺直了身子,却还是看不到光,
你说我不够努力,我说我没有梦想,
街头徘徊着梦,需要与酒邂逅。
浙江温州皮鞋湿,下雨进水不会胖。

原文链接: https://blog.csdn.net/dog250/article/details/125818488

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    TCP 糊涂窗口综合症(silly window syndrome)与 rate-based 流控-CSDN博客

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/405443

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午9:12
下一篇 2023年4月26日 上午9:12

相关推荐