TCP重传 滑动窗口 流量控制 拥塞控制

TCP重传 滑动窗口 流量控制 拥塞控制

学习资源 小林coding 2022.4.7

TCP重传 滑动窗口 流量控制 拥塞控制_第1张图片

重传机制

TCP实现可靠传输的方式之一 通过序列号与确认应答

TCP 当发送端的数据到达接受主机时 接收端主机回返回一个确认应答消息

表示已收到消息

TCP针对数据包丢失的情况 会使用重传机制解决

常见的重传机制

  • 超时重传
  • 快速重传
  • SACK
  • D-SACK

超时重传

在发送数据时 设定一个定时器 超过时间没有收到对方的ACK确认 就会重发该数据

  • 数据包丢失
  • 确认应答丢失
超时时间应该设置为多少

RTT(往返时间)

TCP重传 滑动窗口 流量控制 拥塞控制_第2张图片

RTT是数据从网络一段传送到另一端所需的时间 也就是包的往返时间

超时重传时间是以RTO(超时重传时间)表示TCP重传 滑动窗口 流量控制 拥塞控制_第3张图片

  • RTO较大 重发慢 没有效率 性能差
  • RTO较小 没有丢就重发 重发快 增加网络拥塞 导致更多超市
  • RTO的值应略大于报文往返RTT的值

RTO的值是一个动态变化的值

Linux如何计算RTO

  • 需要TCP通过采样RTT的时间 然后进行加权平均 算出平滑RTT值 值是不断变化的

  • 采样RTT的波动范围

    超时重传策略:超时间隔加倍

    每当遇到一次超时重传的时候 都会下一次超时时间间隔设为先前值的两倍

    两次超时 就说明网络环境差 不适宜频繁发送

快速重传

TCP还有快速重传机制 不以时间为驱动 以数据驱动重传

TCP重传 滑动窗口 流量控制 拥塞控制_第4张图片

  • Seq2没收到 ACK回2
  • 发送端收到了三个ACK=2的确认 直到Seq2还没有收到 就会在定时器国企之前 重传丢失的Seq2
  • 问题:重传之前的一个 还是重传所有的问题

SACK方法

SACK Selective Acknowledgement 选择性确认

需要在TCP头部选项中加一个SACK字段 将缓存的地图发送给发送方

只重传丢失的数据

要支持SACK 在linux下

net.ipv4.tcp_sack

linux2.4之后默认打开

Duplicate SACK

使用SACK告诉发送方 有哪些数据被重复接受了

  • ACK丢包
    • 发现收到数据是重复的 返回SACK
  • 网络延时
    • SACK 与 ACK对比
    • SACK > ACK 说明网络延迟 收到了重复的包

D-SACK好处

  • 让发送方知道 是发出去的包丢了 还是接收方回应的ACK包丢了
  • 可以知道是不是发送方的数据包被网络延迟的
  • 可以知道网络中是不是把发送方的数据包赋值了

滑动窗口

TCP-> 每发送一个数据 都要进行一次确认应答

数据包往返时间越长 通信的效率就越低

TCP引入窗口这个概念 往返时间较长情况下 不会降低网络通信的效率

窗口大小 : 无需等待确认应答 而可以继续发送数据的最大值

窗口实现:操作系统开辟的缓存空间 发送方主机在等到确认应答的消息之前 在缓冲区保存已发送的数据 如果按期收到确认应答 数据可以从缓存区中清除

如果窗口大小为3个TCP段 那么发送方可以连续发送3个TCP段 中途如果有ACK丢失

可以通过下一个确认应答进行确认

如果确认应答报文丢失 可以根据ACK确认 只要发送方收到了ACK700确认应答 意味着700之前的所有数据 都收到了

该模式为累计确认或者累计应答

窗口大小由哪一方确定?

TCP头中有一个字段叫做Window 也就是窗口大小

这个字段是接收端告诉发送端自己还有多少缓冲区可以接受数据

发送端根据接收端的处理能力来发送数据 不会导致接收端处理不过来

通常窗口的大小是由接收方的窗口大小来决定的

发送方发送的数据大小不能超过接收方的窗口大小 否则接收方就无法正常接收到数据

发送方的滑动窗口

TCP重传 滑动窗口 流量控制 拥塞控制_第5张图片

数据全部发送和出去之后 不收到ACK确认之前无法继续发送数据

TCP重传 滑动窗口 流量控制 拥塞控制_第6张图片

如果确认应答之后 发送窗口的大小没有变化 滑动窗口往右面移动五个字节 有5果然字节的数据被响应应答 又变成可用窗口 后续可以继续发送

TCP重传 滑动窗口 流量控制 拥塞控制_第7张图片

程序如何表示发送方的四个部分?

TCP滑动窗口方案中使用三个指针 跟踪四个传输类别中每一个类别的字节 其中两个是绝对指针 一个是相对指针

TCP重传 滑动窗口 流量控制 拥塞控制_第8张图片

  • SND.WND:表示发送窗口的大小(大小是由接收方指定的);
  • SND.UNA:是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节。
  • SND.NXT:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3 的第一个字节。
  • 指向 #4 的第一个字节是个相对指针,它需要 SND.UNA 指针加上 SND.WND 大小的偏移量,就可以指向 #4 的第一个字节了。

可用窗口大小 = SND.WND - (SND.NXT-SND.UNA)

接收方的滑动窗口

TCP重传 滑动窗口 流量控制 拥塞控制_第9张图片

  • #1 + #2 是已成功接收并确认的数据(等待应用进程读取);
  • #3 是未收到数据但可以接收的数据;
  • #4 未收到数据并不可以接收的数据;

其中三个接收部分,使用两个指针进行划分:

  • RCV.WND:表示接收窗口的大小,它会通告给发送方。
  • RCV.NXT:是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号,也就是 #3 的第一个字节。
  • 指向 #4 的第一个字节是个相对指针,它需要 RCV.NXT 指针加上 RCV.WND 大小的偏移量,就可以指向 #4 的第一个字节了。

接收窗口和发送窗口的大小是相等的吗?

不是完全相等 约等于

接收方读取很快 -> 接收窗口可以很快的空缺出来 -> 新的滑动窗口大小可以通过TCP中Windows字段告诉发送方 传输过程存在时延

流量控制

发送方不能无脑发数据 如果对方处理不过来 会导致触发重传 网络流量无端的浪费

TCP提供一种机制可以让发送方根据接收方的实际接受能力控制发送的数据量 这就是所谓的流量控制

  • 客户端接受 服务端发送

  • 假设接收窗口和发送窗口相同 200

    TCP重传 滑动窗口 流量控制 拥塞控制_第10张图片

操作系统缓冲区与滑动窗口的关系

发送窗口和接受窗口中存放的字节数 都是放在操作系统内存的内存缓冲区中的

操作系统的缓冲区 会被操作系统调整

应用进程没办法及时读取缓冲区内容的时候 也会对我们的缓冲区产生影响

TCP重传 滑动窗口 流量控制 拥塞控制_第11张图片

  • 会到导致窗口收缩为0 也就是窗口关闭
  • 当发送方可用窗口变为0时 发送方是机会定时发送窗口探测报文 以便知道接收方的窗口是否发生了变化

当服务器资源非常紧张的时候 操作系统可能会直接减少缓冲区大小 应用程序无法读取缓存数据 会丢包

TCP重传 滑动窗口 流量控制 拥塞控制_第12张图片

为防止这种状况 TCP不允许同时减少缓存又收缩窗口的 采用先收缩窗口 过段时间再减少缓存 避免了丢包情况

窗口关闭

如果窗口大小为0时 组织发送方给接收方传递数据 知道窗口变为非0为止 这就是窗口关闭

窗口关闭潜在风险

接收方向发送方通告窗口大小 通过ACK报文通告

接收方处理完数据后 向发送方通告一个窗口非0的ACK报文 如果中国通告窗口的ACK报文在网络中丢失

TCP重传 滑动窗口 流量控制 拥塞控制_第13张图片

会让双方都等待通知 形成死锁

TCP如何解决窗口关闭潜在死锁

TCP为每个连接设置一个持续定时器 只要TCP连接一方收到对方的零窗口通知

就会启动持续计时器

如果计时器超时 就会发送窗口探测报文 对方在确认探测报文时 给出自己现在的接受窗口大小

TCP重传 滑动窗口 流量控制 拥塞控制_第14张图片

  • 接受窗口仍然为0 那么收到这个报文的一方就会重新启动持续计时器
  • 如果接受窗口不是0 那么死锁打破

窗口探测的次数一般为3此 每次大约30-60s 如果3次过后接受窗口还是0

TCP实现会发RST中断连接

糊涂窗口综合征

接收方忙 -> 来不及取走接受窗口里面的数据 会导致发送方的发送窗口越来越小

如果接收方腾出几个字节并且告诉发送方现在有几个字节的窗口

发送方会全部发送

TCP+IP头有40字节 开销太大 不经济

TCP重传 滑动窗口 流量控制 拥塞控制_第15张图片

  • 让接收方不通告小窗口给发送方
  • 让发送方避免发送小数据

怎么让接收方不通告小窗口

接收方策略:

当窗口大小小于min(MSS,缓存空间/2) 小于MSS与1/2缓存空间的最小值

直接向发送方发送窗口为0

等空间大了再通知发送方

如何让发送方避免发送小数据?

发送方通常策略:

Nagle算法 延时处理

  • 等到窗口大小>=MSS或者数据大小>=MSS
  • 收到之前发送数据的ack回包

可以在 Socket 设置 TCP_NODELAY 选项来关闭这个算法(关闭 Nagle 算法没有全局参数,需要根据每个应用自己的特点来关闭)

setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int));

拥塞控制

拥塞控制与流量控制

流量控制 -> 避免发送方的数据填满接收方的缓存

但是并不知道网络中发生了说明

计算机网络处在一个共享的环境 有可能会因为其他主机之间的通信使得网络拥堵

当网络出现拥堵时 如果继续发送大量数据包 可能会导致数据包时延 丢失等 这时TCP就会重传数据 一重传就会导致网络负担更重 会导致恶性循环

拥塞控制 -> 避免发送方的数据填满整个网络

发送方调节发送数据的量 -> 定义了一个拥塞窗口的概念

什么是拥塞窗口 和发送窗口有什么关系?

拥塞窗口是发送方维护的一个状态变量 (cwnd)

会根据网络的拥塞程度动态变化

发送窗口 = 拥塞窗口和接受窗口的最小值

变化规则

  • 网络没有拥塞 cwnd增大
  • 网络拥塞 cwnd减少

如何知道是否拥塞?

如果发生超时重传 就会认为网络出现了拥塞

拥塞控制有哪些控制算法?

  • 慢启动
  • 拥塞避免
  • 拥塞发生
  • 拥塞恢复

慢启动

发送方每收到一个ACK 拥塞窗口大小+1

TCP重传 滑动窗口 流量控制 拥塞控制_第16张图片

慢启动涨到什么时候是个头呢?

慢启动门限 : ssthresh 状态变量

  • cwnd < ssthresh 慢启动
  • 拥塞避免算法

拥塞避免算法

ssthresh大小一般是65535字节

每收到一个ACK cwnd增加1/cwnd

TCP重传 滑动窗口 流量控制 拥塞控制_第17张图片

线性增长

当触发了重传机制 也就进入了拥塞发生算法

拥塞发生算法

  • 超时重传
  • 快速重传

超时重传 拥塞发生

这个时候,ssthresh 和 cwnd 的值会发生变化:

  • ssthresh 设为 cwnd/2
  • cwnd 重置为 1

TCP重传 滑动窗口 流量控制 拥塞控制_第18张图片

发生快速重传的拥塞发生算法

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd;
  • 进入快速恢复算法

快速恢复

正如前面所说,进入快速恢复之前,cwndssthresh 已被更新了:

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd;

然后,进入快速恢复算法如下:

  • 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);
  • 重传丢失的数据包;
  • 如果再收到重复的 ACK,那么 cwnd 增加 1;
  • 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;

TCP重传 滑动窗口 流量控制 拥塞控制_第19张图片

TCP重传 滑动窗口 流量控制 拥塞控制_第20张图片

你可能感兴趣的:(计算机网络,网络协议)