TCP的流量控制机制与滑动窗口

一、滑动窗口实现

所谓的流量控制, 就是告诫对方发送速率不要太快, 要让接收来来得及接收数据。

形容如下;

甲向乙发送数据。经过TCP三握手连接以后, 当乙告诉甲:“我的接受窗口rwnd = 400”(这里rwnd表示receiver window的意思)。所以,发送方的发送窗口不能超过接收方给出的接受窗口的数值。而TCP窗口的单位是字节, 而不是报文段。


例子解释如下:

假设每个报文的长度为100字节, 报文段的序号初始值设置为1。



1、主机乙对该传输过程进行了三次流量控制。(按道理说,seq 1 和 sql 101发送后主机乙放回的rwnd = 200, 但是在该应答中返回的是300, 那可能是因为主机B调用recv函数读取了100字节, 后续若遇到此类情况, 皆是如此处理)。

2、seq因为没有发送成功,第一次流量控制ack= 201,rwnd = 300; 在经过三次发送过, seq = 201, 再次发送属于超时重传。

3、最后返回的ACK应答中, rwnd = 0, 表示甲主机不能再向乙主机传输数据了。 等待乙主机的进程读取数据。

4、如果乙主机的缓存空间又空闲了。 那么乙主机将会向甲主机发送ACK = 1, rwnd = 400的应答, 如果该应答在传输的过程中丢失了。甲主机将会一直等待乙主机的非零窗口通知, 而乙主机也一直在等待甲主机发送的数据,在没有其他措施的情况下, 这种相互等待将会一直死锁下去


由4小点我们引入了一个新的措施, 叫做持续及时器:

*持续计时器:

TCP连接的任何一段, 如果收到了0窗口通知, 那么将会启动持续计时器。当持续计时器的时间到了后, 该端将会发送一个零窗口的探测报文段(携带一个字节的数据),如果还是收到了零窗口通知, 将继续重新启动计时器, 重复该步骤, 直到打破死锁位置。



二、滑动窗口机制


由上图所示, 甲主机的发送窗口为20, 乙主机的接受窗口是20.

1)、甲主机开始接收到了来自乙主机ack = 29, win = 20的窗口通知。 那么甲主机就发送序号为[29,49)里面的数据, 理想乙主机希望接受[29,49)序号的数据。

2)、可能因为序号为31的字节数据丢失、又或者是滞留在网络当中, 导致数据不能完全接受, 那么乙主机发送ack = 31, win = 20的通知窗口给对端

3)、甲主机有接受ack = 31, win = 20,的通知窗口。 接受并且发送序号为[31,51)里面的数据, 又因为可能序号为35的字节丢失重复以上操作


三、试验分析

通过客户端不断向服务写入数据, 但是服务器端并不读取任何数据进入睡眠状态。

服务器程序代码片段:

for(;;){
    pause();
    n = read(confd, buf, MAXLINE);
    printf("n = %d\n", n);
    if(n < 0){
        if(errno == EINTR) continue;
        else{
            fprintf(stderr, "read error \n");
            break;
        }
    }
    else if(n == 0) break;
    else{
        buf[n] = 0;
        write(confd, buf, n);
    }
}

客户端程序代码片段

for(;;){
    write(sockfd, sendbuf, MAXLENGTH);
    usleep(5);
}


抓包结果:


四、总结

1、了解滑动窗口的含义。

2、怎么通过发动窗口来控制流量的(即工作流程)

3、拓展:在三中的试验结果win = 295 275, 远小于接受缓冲区的空闲缓存区大小值(提示:wscale, 窗口大小偏移因子, 在TCP三路握手中, 可以看到这个值)

猜你喜欢

转载自blog.csdn.net/xiaomiCJH/article/details/76643559
今日推荐