计网查漏补缺-运输层协议

TCP中序号的单位是什么,滑动窗口的单位是什么?

TCP报文格式

  • 序列号:它表示发送数据的位置,假设当前的序列号为 s,发送数据长度为 l,则下次发送数据时的序列号为 s + l。在建立连接时通常由计算机生成一个随机数作为序列号的初始值。
  • 确认应答号:它等于下一次应该接收到的数据的序列号。假设发送端的序列号为 s,发送数据的长度为 l,那么接收端返回的确认应答号也是 s + l。发送端接收到这个确认应答后,可以认为这个位置以前所有的数据都已被正常接收。
  • 数据偏移:TCP 首部的长度,单位为 4 字节。如果没有可选字段,那么这里的值就是 5。表示 TCP 首部的长度为 20 字节。
  • 控制位:改字段长度为 8 比特,分别有 8 个控制标志。依次是 CWR,ECE,URG,ACK,PSH,RST,SYN 和 FIN。在后续的文章中你会陆续接触到其中的某些控制位。
  • 窗口大小:用于表示从应答号开始能够接受多少个 8 位字节(单位)。如果窗口大小为 0,可以发送窗口探测。

三次握手中,第三次(发送ACK) 确认包丢失怎么办

三次握手其实解决了第二步的数据包丢失问题。那么第三步的 ACK 确认丢失后,TCP 协议是如何处理的呢?

按照 TCP 协议处理丢包的一般方法,服务端会重新向客户端发送数据包,直至收到 ACK 确认为止。但实际上这种做法有可能遭到 SYN 泛洪攻击。所谓的泛洪攻击,是指发送方伪造多个 IP 地址,模拟三次握手的过程。当服务器返回 ACK 后,攻击方故意不确认,从而使得服务器不断重发 ACK。由于服务器长时间处于半连接状态,最后消耗过多的 CPU 和内存资源导致死机。

正确处理方法是服务端发送 RST 报文,进入 CLOSE 状态。这个 RST 数据包的 TCP 首部中,控制位中的 RST 位被设置为 1。这表示连接信息全部被初始化,原有的 TCP 通信不能继续进行。客户端如果还想重新建立 TCP 连接,就必须重新开始第一次握手

fin_wait1,fin_wait2,close_wait,last_ack分别是客户端还是服务端的状态?

TCP四次挥手

关闭连接的最后一个 ACK 丢失怎么办

实际上,在第三步中,客户端收到 FIN 包时,它会设置一个计时器,等待相当长的一段时间。如果客户端返回的 ACK 丢失,那么服务端还会重发 FIN 并重置计时器。假设在计时器失效前服务器重发的 FIN 包没有到达客户端,客户端就会进入 CLOSE 状态,从而导致服务端永远无法收到 ACK 确认,也就无法关闭连接。

那是不是服务端永远无法关闭连接了?

当然不是,如果服务器一直没收到客户端的ACK,会触发TCP的保活计时器,如果两个小时没收到客户端的消息,服务端会每隔75秒发送一次探测报文,客户端无响应,服务端就认为客户端出故障了,接着就关闭自己了。

TCP拥塞控制算法,流量控制的区别?

总而言之

拥塞控制——律己,约束自身发送行为,不至于造成网络拥塞。
流量控制——律人,你发送方给我悠着点,我的窗口空间还剩下XX,别把我塞爆了。

拥塞的定义:

  • 当一个报文发送后,开启了超时重传计时器,规定时间内还没有接收到确认报文则认为是发生了丢包,我们将次视为网络拥塞的一个标志事件。
  • TCP采用滑动窗口搭配选择重传/快速重传(而不是Go Back To N)来保证传输效率及传输报文的有序,收到失序报文后立即发送三个重复ACK来获取中间缺失的报文段。这种情况相较上一种没那么严重。

拥塞避免:

为什么要拥塞避免/拥塞控制?

若出现网络拥塞,分组将发生丢失,此时发送方由于接受不到ACK继续重传报文,导致网络更拥塞,我们需要对发送方加以约束避免这种情况的发生。

怎么实现?

发送方需要维护一个叫做 拥塞窗口(cwnd) 的状态变量(这知识一个状态变量,实际决定发送方发送上限的是发送方的窗口大小:详见 滑动窗口)

让拥塞窗口cwind缓慢地增大,每经过一个往返时间RTT就把发送方的拥塞窗口cwind加1,而不是加倍。这样拥塞窗口cwind线性缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
  无论慢启动开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢启动门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwind重新设置为1,执行慢启动算法。目的是迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

控制过程

  • 慢开始:

    最初执行慢开始,令 cwnd = 1 ,只能发送一个报文段,当收到确认后,cwnd *= 2 ,故之后可发送的报文段个数为 2,4,6,8…

  • 拥塞避免:

    设置一个慢开始门限 ssthresh(该变量将在超时发生时确定),当 cwnd > ssthresh ,进入拥塞避免阶段:每个轮次(未超时,收到ACK确认报文)只令 cwnd += 1

  • 快速重传:

    当接收方接收到失序报文时将发生快速重传:如,接收到了报文段 M1,M2,M4,那么久连续三次发送对M2的 ACK 报文,提醒发送方发送缺失的 M3。

    发送方收到三个重复的 ACK 后,直到 M3 缺失,快速重传 M3。

  • 快速恢复:

    发生了快速重传,只是出现了个别报文段的丢失,而不是 超时 所标志的网络拥塞事件,此时使用快速恢复:令 ssthresh = cwnd / 2, cwnd = ssthresh,然后直接进入拥塞避免阶段。

拥塞控制

流量控制:

如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。

TCP的流量控制是利用滑动窗口机制实现的,接收方在返回的ACK中会包含自己的接收窗口的大小,以控制发送方的数据发送。

但是当某个ACK报文丢失了,就会出现A等待B确认,并且B等待A发送数据的死锁状态。为了解决这种问题,TCP引入了 持续计时器(Persistence timer),当A收到 rwnd=0 时,就启用该计时器,时间到了则发送一个1字节的探测报文,询问B是很忙还是上个ACK丢失了,然后B回应自身的接收窗口大小,返回仍为0(A重设持续计时器继续等待)或者会重发 rwnd=x 。

TCP滑动窗口

发送方和接收方各自维护有一个窗口,用来暂时存放字节流。接收方通过TCP报文中的窗口字段告诉发送方 自己的窗口大小,发送方据此调整自己窗口的大小,从而实现了流量控制,不至于把接收方塞爆。

发送方窗口内的所有字节都允许发送,若窗口左边的字节皆已发送并受到确认,就可向右滑动直到第一个未被确认的字节。

接收窗口只会对 窗口内最后一个按序到达的字节进行确认。

TCP 粘包半包现象的解决方案

**粘包、半包:**发送若干数据包到接收方,接收时将若干个包当做一个包读取,或只读取部分包的现象。

发送方的原因:

TCP默认采用 Nagle 算法(减少网络中的报文数量),其主要步骤有:

  1. 只有上一个分组得到确认,才会发送下一个分组
  2. 收集多个小分组,在一个确认到来时打包一起发送。

接收方原因:

收到数据包时,应用层并不会立即处理,TCP将接收到的数据暂存到缓存,应用主动从缓存读取分组。

如何解决:

  1. 双方约定,发送定长的数据包
  2. 包的尾部加上分隔标记,例如 “ \r\n ” ,FTP 协议就是这么干的。坏处是让若正文中也有 “ \r\n ” 可能会误判进而导致错误分隔。
  3. 包头加上包体的长度,包头为定长 4 byte ,说明包体的长度。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,邮件至 708801794@qq.com

文章标题:计网查漏补缺-运输层协议

文章字数:2.3k

本文作者:梅罢葛

发布时间:2020-11-04, 13:01:43

最后更新:2020-11-04, 14:59:12

原始链接:https://qiurungeng.github.io/2020/11/04/%E8%AE%A1%E7%BD%91%E6%9F%A5%E6%BC%8F%E8%A1%A5%E7%BC%BA-%E8%BF%90%E8%BE%93%E5%B1%82%E5%8D%8F%E8%AE%AE/
目录
×

喜欢就点赞,疼爱就打赏