【Linux从青铜到王者】tcp协议2

滑动窗口

滑动窗口是什么

上篇提到如果两端发送数据如果是一发一收那就是串行,效率很低,所以可以一次发送多个报文,一次也可以接受多个报文,可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)

那么是怎么发送多个报文的呢?靠的就是滑动窗口这个大杀器

滑动窗口是什么?是为了让tcp并发地发送大量暂时不需要ACK的数据段,从而提高发送效率的解决方案(这里也涉及流量控制的解决方案,和重传机制也有关系!)

如果学习过双指针算法的同学可能听到滑动窗口这个名字很熟悉,其实这里就是类似的

之前我们说过可以把缓冲区当做一个单位大小为char的数组,然后有两个指针win_start和win_end分别指向滑动窗口的起始位置和结束位置

这样发送缓冲区就被分成了三个区域:

          滑动窗口的左边区域,处于滑动窗口的区域,滑动窗口的右边区域

分别对应已发送已确认可以直接发送但是尚未确认未发送或者没数据的区域

下图为示范例子:

  • 窗口大小就是指无需等待确认应答而可以继续发送数据的最大值。图中,窗口大小为4个段,也就是4000个字节。
  • 发送前四个段的时候, 不需要等待任何ACK, 直接发送。
  • 收到第一个ACK后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推。
  • 操作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉——所以一个数据被发送后,不能立马被移除
  • 窗口越大, 则网络的吞吐率就越高

滑动窗口在哪里?

滑动窗口本质上就是发送缓冲区的一个区域

滑动窗口怎么理解?

【win_start,win_end】:滑动窗口!!——本质就是两个数组下标充当指针作用

win_start=确认序号

win_end=win_start(确认序号)+win(接收方的接受能力)——16位窗口大小

所谓的窗口滑动,本质就是下标移动

因为滑动窗口发送的是可以直接发送尚未确认的数据,所以要考虑对方的接受能力,所以滑动窗口的大小由对方的接受能力决定!!!(后续会有变化)

那么最开始的时候,我还没发送数据的时候,滑动窗口的大小是多大?

所以在三次握手的时候,滑动窗口的大小,双方已经协商完毕

滑动窗口的变化以及流量控制

滑动窗口可以往左移动吗?

不可以,win_start=确认序号,而确认序号=序号 +1的,所以滑动窗口只可能往左移动

滑动窗口的大小不变吗?变大?变小?为0?

当确认一个报文后又发送一个报文的时候,滑动窗口的大小就是不变的

当一次发了四五个报文,只有前面两个应答了,那么win_start+=2个报文的长度,滑动窗口也就变小了。后面全部报文都应答了,win_end+=三个报文的长度,滑动窗口也就变大了

所以不变,变大和变小都是可以的——流量控制!!!

接收方能力弱:我就发慢点

接收方能力强:我就发快点

变大变小不变都行,这才叫控制

如果滑动出去,越界了怎么办?把发送缓冲区想象成环形结构即可!!!(环形数组可以用数组来模拟实现)

这里也体现到上篇提到的如果报文发送了,还没应答,就不能丢弃,暂时存起来,存在哪?滑动窗口里

报文丢失

一次发多个数据,那么肯定会有上篇讲的丢失报文的问题,那么报文丢了怎么办?

我们可以将报文丢失分为三类:最左侧丢失,中间丢失,右侧丢失

如果发了序号2000,3000,4000,5000的四个报文,正常情况下发送方应该收到确认序号为2001,3001,4001,5001的ACK

最左侧丢失就是2001ACK没收到,那么此时后面的确认序号就不再是3001,4001,5001了,而是1001,因为确认序号的定义是该序号之前的数据,全部收到

所以连续接收到三个1001ACK,但是明明发的是2000,3000,4000,5000,所以就可以推测出是2000报文丢失了,所以会补发2000报文!!!

如果是中间丢失,也就是3001丢失,那么发送方是接收到2001ACK的,所以窗口会向右移动一个长度,此时中间丢失就变成最左边丢失,重复以上动作即可

如果是最右侧丢失,那么结果还是一样的,窗口不断右移直到丢失的报文成为最左侧,变成最左侧丢失的情况,然后重复上述操作!

总结:不管是什么丢失,最后都会变成最左侧丢失

这里涉及到一个重传机制

快重传:如果连续收到三个同样的确认序号的时候,会立即将对应的报文进行补发!!!

有人会想了,都有快重传了,听名字就挺快的,还要超时重传干什么?

细看的话会发现快重传是有条件的,要连续收到三个同样的确认序号,不是连续的话只能超时重传了

所以超时重传是兜底的,快重传是提高效率的重传策略,两者互相配合

在滑动窗口这里,可以充分体会到确认序号的的价值!!!

还有将缓冲区视为字节环形结构的作用——有了序号和确认序号,保证了可靠性——发送成功或者失败都100%知道!!!

到这里不得不赞叹tcp的设计,几个字段互相配合不仅仅保证了可靠性,还实现了效率的提升

拥塞控制

到目前为止我们讲的都是两个主机之间的,两个主机之间通信还要经过网络这一环节

假设有一天网络突然瘫痪(网络非常繁忙)了,发送的报文迟迟未被接收,那么此时要进行超时重传吗?

如果这时进行超时重传,注意此时不再是两台主机之间通信,可能有很多台主机都向你超时重传发送信息,注意此时网络已经瘫痪,超时重传等于再发一次信息,无异于压死骆驼的最后一根稻草,让网络雪上加霜

所以此时不能进行网络重传

当出现小面积丢包的时候,认为是丢包,进行超时重传

当出现大面积丢包的时候,认为是网络出现问题,不超时重传,而是拥塞控制

什么是拥塞控制呢?就是先试探,慢慢发,随着你应答的次数增多而显著提高发送的数据量

滑动窗口决定了我们单次发送数据量的多少——所以滑动窗口的大小不仅与对方的接受能力有关,还要考虑网络的状态

滑动窗口=min(拥塞窗口大小,对方的窗口大小)

拥塞窗口本质就是一个数字,当发送数据量超过拥塞窗口的时候,有很大的概率会引起网络拥塞

拥塞窗口=2^n,就是个指数函数。可以发现该函数完美切合要求,慢启动,快增长。

前期慢,增长快——前期慢是为了试探网络环境如何,增长快是为了尽快进行正常网络的通信

当拥塞窗口的值超过阈值的时候,拥塞窗口就会变成线性增长,变化规律如图所示,就不赘述

我们发送数据的时候,就是按照图片的规律来发送吗?当然不是,发送数据靠什么?靠滑动窗口?滑动窗口win_start=ack,win_end=min(拥塞窗口大小,对方窗口大小)

所以可能发送到一半就按照对方窗口的大小发送了

但是拥塞窗口必须一直在变化,因为网络的状态要一直探测

tcp的保活机制(心跳机制)

机器掉电,网线断开的时候,tcp内部有一个计时器,当超过固定时间后仍未应答则自动关闭连接,但是tcp的时间定的太长了,一般更推荐在应用层完成

listen的第二个参数

全连接队列

饭店排队场景类似

如果一个饭店里很多人用餐没有位置了,此时又新来了客人,你直接对客人说走吧没位置了,那肯定会被老板喷个狗血淋头,因为等里面的客人吃完了,如果此时又没新的客人来,高峰期的时候一些座位就会被闲置了

如果你在外面放了一些椅子,让客人在外面等,这时里面的人用完餐了,外面的人就可以直接进去用餐了,高峰期里面的位置被闲置的概率大大降低

但是你也不能在外面摆太长,比如摆个几百张,除了前面几十张等得起,后面的人要等的时间太久了,而且椅子也是占空间的,外面的地可不是都是你们店的

上面的饭店就类似应用层,客人就是连接,外面摆的椅子就是全连接队列,全连接队列不能太长

相关问题

connect参与三次握手吗?

connect参与三次握手,发送SYN请求后,双方操作系统自动完成

accept参与三次握手吗?

当一个服务器通过bind函数开始监听该套接字上的连接请求,一旦有客户端尝试建立连接,三次握手成功后,服务器端的accept调用才会返回,从全连接队列中获得一个新的套接字

所以是不参与的,是发生在三次握手之后的

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值