TCP/IP详解 TCP的超时与重传(21)

2021-05-28  本文已影响0人  helinyu

PS :

  1. 对TCP超时和重传机制的详细研究。 第一个例子是一个丢失的建立连接的SYN, 并观察了在随后的重传和超时中怎么使用指数退避方式
  2. TCP计算往返时间并使用这些测量结果来维护一个被平滑的RTT估计器和被平滑的均值偏差估计器。 这两个估计器用来计算下一个重传时间。 许多实现对每个窗口仅测量一次RTT。 Karn算法在分组丢失时可以不测量RTT就能解决重传的二义性问题。
  3. 详细例子包括3个丢失分组, 使我们看到TCP的许多实际算法:慢启动、拥塞避免、快速重传和快速恢复。 也能够使用拥塞窗口和慢启动门限来手工计算TCP的RTT估计器,并将这些值与跟踪输出的时机数据进行比较。
    4)以多种ICMP差错对TCP连接的影响以及TCP怎么允许对数据重新分组。 观察到“软”的ICMP差错没有引起TCP连接终止, 但这些差错被保存以便在连接非正常中止时能够报告这些软差错。

TCP提供可靠的传输层。 它使用的方法之一就是确认从另一端收到的数据。 但是数据和确认都可能会丢失。 TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认,它就重传该数据。 对于实现而言, 关键在于超时和重传的策略,即:怎么决定超时间隔和如何确定重传的评率

每个TCP连接有4个不同的定时器

  1. 重传定时器使用与当希望收到另一端的确认。在规定时间内容,发送方需要接收到另一端发出的接收报文确认。 我们将讨论这个定时器以及相关的问题。 eg:拥塞避免
  2. 坚持(persist)定时器 使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。 (22)
  3. 保活(keepalive) 定时器 用于检测一个空闲连接的另一端是否依然还保持连接。 (23)
  4. 2MSL 定时器 测量一个连接处于TIME_WAIT状态时间。 前面已经讲了18.6

TCP 重传机制


建立一个连接,发送高一些分组来证明一切正常,然后拔掉电缆,发送更多的数据,观察TCP的行为
TCPDump这个过程
  1. 第 1 、 2 和 3 行 表 示 正 常 的 T C P 连 接 建 立 的 过 程 , 第 4 行是“ h e l l o , w o r l d ”( 1 2个 字 符 加 上 回 车 和 换 行 ) 的 传 输 过 程 , 第 5 行 是 其 确 认 。 接 着 我 们 从 s v r 4 拔 掉 了 以 太 网 电 缆 , 第 6 行表示 “ a n d h i ” 将 被 发 送 。 第 7 ~ 1 8行 是 这 个 报 文 段 的 1 2 次 重 传 过 程 , 而 第 1 9 行 则 是 发 送 方 的 T C P 最
    终放弃并发送一个复位信号的过程。
  2. 重传的的时间: 1 、 3 、 6 、 1 2 、 2 4 、 4 8 和多个 6 4。 基本上时间都是增加一倍,然后到64s。 —— 这些倍乘的关系称为: 指数退避(exponential back off)
  3. 首 次 分 组 传 输 ( 第 6 行, 2 4 . 4 8 0 秒 ) 与 复 位 信 号 传 输 ( 第 1 9 行, 5 6 6 . 4 8 8 秒 ) 之 间 的 时 间 差 约为 9 分 钟 , 该 时 间 在 目 前 的 T C P 实 现 中 是 不 可 变 的 。 【这个时间值是可以更改的】

通过上面我们直达搜:1)时间上的指数避退 2)复位的时间


往返时间测量

意义: TCP超时与重传中最重要的部分就是对一个TCP连接的往返时间(RTT)的测量。由于网络状况多变性, RTT时间经常会发生变化, TCP应该跟踪这些变化并相应地改变超时重传时间。

RTT(RTO)指的测量

1)RFC793被平滑的RTT评估器 最初TCP规范使TCP使用低通过滤器来更新一个被平滑的RTT估计器(记为O)。

这个因子是一个推荐值0.9的平滑因子。 每次进行新测量的时候, 这个平滑的RTT将得到更新。 也就是90%来自估计值, 10% 来自新的测量。 这个算法在给定这个随RTT的变化而变化的平滑因子的条件下, 重传超时时间RTO(Retransmission Time out)的值应该设置为 RTO = R@ , 这里的@推荐值是2的时延离散因子。 也就是RTO值 是RTT值的2倍
缺陷: 在RTT变化范围很大时, 使用这个方法无法跟上这种变化, 从而引起不必要的重传。 【当网络已经处于饱和状态时,不必要的重传会增加网络的负载】
  1. Jacobson 跟踪RTT的方差: 在往往返拜年话欺负很大的情况下,基于均值和方差来计算RTO,```比用均值的常数倍来计算RTO提供更好的对网络传送数据状况的表示方法。



    A是被平滑的RTT(均值的估计器), D则是被平滑的均值偏差 , Err是刚得到的测量结果与当前的RTT估计器之差。 A和D均被用于计算下一个重传时间(RTO)。增量g起平均作用, 取为1/8(0.125)。偏差的增益是h, 取值为0.25. 当RTT变化时, 较大的偏差增益将使RTO快速上升。
    比较: Jacobson计算RTO的公式依赖于被平滑的RTT和被平滑的均值偏差, 而RFC 793 方法则是使用了被平滑的RTT的一个倍数。

重传多义性问题 : 在一个分组重传时候回产生这样的一个问题:假如一个分组被发送,当超时发生时, RTO正进行植树退避, 分组以更长的RTO进行重传, 然后收到一个确认。 那么这个ACK是针对第一个分组的还是针对第二个分组?
Karn 算法: 当一个超时和重传发生时, 在重传数据的确认最后到达之前,不能更新RTT估计器。 也就是这个RTT不管,就会不更新。 原因:因为我们并不知道 A C K 对 应 哪 次 传 输 ( 也 许 第 一 次 传 输 被 延 迟 而并没有被丢弃,也有可能第一次传输的 A C K 被延迟)。并且,由于数据被重传, RTO已经得到了一个指数退避,我们在下一次传输时使用这 个退避后的 RTO 。对一个没有被重传的报文段而言,除非收到了一个确认,否则不要计算 新的RTO。

PS : 评估RTO的两种方式


往返时间RTT的例子

执行了32个1024字节的操作。 由于slip和bsdi之间的MTU为296字节,因此这些操作会产生28个报文段,每个报文段包含256字节的用户数据。整个传输过程的时间约为45s, 我们观察到一个超时和三次重传。

大多数BSD的TCP实现在任何时候对每个连接仅测量一次RTT值。 在发送一个报文段时, 如果给定连接的定时器已被使用,则该报文段不被计时。

对每个连接而言,除了这个滴答计数器,报文段中数据的起始序号的也被记录下来。当收到一个包含这个序号的确认后,改定时器就被关闭。如果ACK到达时时数据没有被重传(定时器没有超时),则被平滑的RTT和被平滑的均值偏差将给予这个新的测量值进行更新。

发送了128个报文被传送手机了18个RTT采样

21.4.2 RTT估计器 【平滑的RTT和平滑的均值偏差】

  1. 变量A和D被初始化为0和3秒;
  2. RTO= 0+ 2 *3 [这个只是在初始的时候使用]
    第一个数据报文段的ACK 到达时, 经历了3个时钟滴答, A和D被初始化:
    A= M+ 0.5 = 1.5 + 0.5 (3个始终滴答, M取值为1.5)
    D = A/2 = 1;
    使用 第一个RTT的测量结果M 对估计器进行首次计算的初始值。 计算RTO为: RTO= A+4D = 2 + 4 *1 = 6s
    RTO = A + 4D 【一般的计算】 当第二个数据报文段的ACK到达时, 经历一个时钟滴答(0.5秒),

Err = M - A = 0.5 - 2 = -1.5
A= A + gErr = 2 - 0.125 * 1.5 = 1.8125
RTO = A+ 4D = 1.825 + 4 *1.125 = 6.3125
采用上面公式计算的Err 、A 和D的值与实际使用的定点计算方法得到结果有一些微小的差别。 后一种方法得到的RTO的值为6s(因为计算机是采用了移位操作,而非6.3125s)


拥塞举例:


在时刻 10、14、 31 附近发生了3个重传。 我们还可以看到在这3个点中只进行了一次报文段的重传, 因为只有一个点下垂低于向上的斜率。


拥塞避免算法

有两种分组丢失的指示:超时和接收到重复的确认。
—— 使用超时作为丢包的指示,需要一个号的RTT算法。
接收到重复的确认重复的ACK: 表示后面的数据已经到了,但是前面的数据还没有到,所以ack返回了前面的ack, 接收到多少个同样的ACK才表示这个数据报丢掉? 3个重复的ack】

  1. 拥塞避免算法是一种处理丢失分组的方法
  2. 改算法假定由于分组收到损坏引起的丢失是非常少的(远远小于1%), 因此分组丢失就以为这在源主机和目的主机之间的某处网络上发生了拥塞。
  3. 拥塞避免算法和慢启动算法是有两个目的不同、独立的算法。 当拥塞发生时,我们希望降低分组进入网络的传输率,于是可以调用慢启动来实现这一点。 在实际中,这两个算法通常在一起实现。
  4. 拥塞避免和慢启动都是发送方使用的流量控制【慢启动允许一方发送连续未经确认的分组的增加方式采用的指数增加, 拥塞避免允许一方发送连续的未经确认的分组的增加方式采用线性增加】,而通告窗口则是接收方进行的流量控制。 拥塞避免是发送方对网络可能发生拥塞的估计, 而后者则是与接收方分配给该连接的接收缓存大小有关。

拥塞避免算法和慢启动算法需要对每个连接维持两个变量: 已给拥塞窗口cwnd 和 一个慢启动门限ssthresh 。 算法的工作如下:

  1. 对一个给定的连接,初始化cwnd为1个报文段, ssthresh 为65535个字节。
  2. TCP发出未经确认的报文总大小不能超过cwnd和接收方通告窗口的大小。
  3. 当拥塞发生时(超时或收到重复确认),ssthresh 被设置为当前窗口大小的一半【cwnd 和接收方通告窗口大小的最小值,但最少为2个报文段】。此外,如果是超时引起的拥塞,则cwnd被设置为1个报文段【这就是慢启动】
  4. 当新的数据被对方确认时, 就增加cwnd,但增加的方法依赖于我们是否正在进行慢启动或拥塞避免。如果cwnd小于或等于ssthreash, 则正在进行慢启动,否则正在进行拥塞避免。 慢启动一直持续到我们回到当拥塞发生是所处位置一半停止(因为我们记录了在步骤3中给我们制造麻烦的窗口大小的一半,就是ssthresh),接下来就是执行拥塞避免。
  5. 慢启动算法: 初始设置cwnd 为1个报文段, 此后,每收到一个确认就加1 ; 这会使窗口在每个RTT时间内按指数方式增长,发送一个报文段,然后是2个接着是4个。
  6. 拥塞避免算法要求每次收到一个确认时将cwnd 增加1/cwnd . 与慢启动的指数增加比起来, 这是一种增加性增长(additive increase)。 我们希望在一个往返时间内最多为cwnd增加一个报文段(不管在这个RTT中收到了多少个ACK), 然而慢启动将根据这个往返时间中所收到的确认的个数增加cwnd。

有点疑惑的地方: 就是出现了拥塞之后,是又从1开始还是直接从一半开始的呢? 如果是超时: cwnd 就重置为1。

图中: 假定cwnd 为32个报文段时发生拥塞(超时引起)。 于是设置ssthresh 为16个报文段,而cwnd为1个报文段。 在时刻0发送一个报文段, 并假定在是可1接收到它的ACK, 此时cwnd增加为2. 接着发送了2个报文段, 并假定时刻2接收到了它们的ack,于是cwnd增加为4(对每个ack增加1)。 这种指数增加算法一直精心到时刻3和4之间收到8个ack后cwnd等于ssthresh时才停止,从此刻开始,,cwnd以线性方式增加,在每个往返时间内最多增加1个报文段。

拥塞避免算法:线性增长的过程,上面的例子是慢启动和拥塞避免算法的集合


快速重传与快速恢复算法

  1. 快速重传算法: 如果一连串收到3个或3个以上的重复ack【重复确认ack,这个也是拥塞的表现,具体是怎么样的?】, 就非常可能是一个报文段丢失了。 于是我们就重传丢失的数据报文段, 而无需等待超时定时器溢出。
  2. 快速回复算法: 快速重传后执行的不是慢启动算法而是拥塞算法。 没有执行慢启动的原因是: 收到重复的ACK不仅仅告诉我们一个分组丢失了,还告诉我们一个数据报离开网络顺利的到达接受者。 这是由于接收方只有在收到另一个报文段并发现这个报文不是我们当前需要序号的报文才会产生重复的ACK, 说明有一个报文不是我们当前需要的序号的报文才会产生重复的ACK ,说明有一个报文段已经离开了网络并进入接收方的缓存。 也就是说, 在首发,两段之间仍然有流动的数据,而我们不想执行慢启动来突然减少数据流。

快速恢复算法

  1. 当收到第3个重复的ACK时, 将ssthresh 设置为当前拥塞窗口cwnd的一半。 重传丢失的报文段。 设置cwnd为ssthresh 加上3倍的报文段大小。
    ssthresh 本应立即设置为当重传发生时正在起作用的窗口大小的一半,但是在接收到重复ACK过程中的cwnd允许保持增加,这是因为这个重复的ACK表示一个报文段已经离开了网络,收到3个重复的ACK,表示有3个报文离开了网络,并被接收TCP缓存了这几个报文段,正在等待所缺数据的到达。
  2. 每次收到另一个重复的ACK时, cwnd增加1个报文段大小并发送1个分组。
  3. 当下一个确认新数据的ACK到达时, 设置cwnd为ssthresh(在第1步中设置的值)。 这个ACK应该是在进行重传后的一个往返时间内对步骤1冲重传的确认。 另外,这个ACK 也应该是对丢失的分组和收到的第一个重复的ACK之间的所有中间报文段的确认。 这一步采用的是拥塞避免, 因为当分组丢失时我们将当前的速率减半。
要看完拥塞的例子

按每条路由进行度量
新的TCP实现在路由表项中维持粗多我们在前面已经介绍过的指标。 但一个TCP连接关闭时, 如果已经发送改了足够多的数据来获得有意义统计的资料, 且目的节点的路由表项不是一个默认的表项,那么下列信息就曹村在路由表项中以备下次使用: 被平滑的RTT,被平滑的均值偏差以及慢启动门限。 所谓 “足够多的数据”是指一个窗口的数据,这样就可得到16个RTT采样。
当建立一个新的连接时, 无论是主动还是被动,如果该连接将要使用的路由表项已经有这些度量的值,则用这些度量来对相应的变量进行初始化。


ICMP 的差错: 源站抑制、 主机不可达、网络不可达

当前BSD对ICMP错误的处理是:

  1. 接收到的源站抑制ICMP差错报文: 拥塞窗口cwnd被置为1个报文大小,开始慢启动,但是慢启动门限ssthresh没有变化,所以发送窗口将打开知道它或者充分利用首发双方的链路(受窗口大小和往返时间的限制)或者发生了拥塞。
  2. 接收到的主机不可达或网络不可达的ICMP差错都被忽略, 因为这两个差错都被认为短暂现象。 这有可能是由于网络发生故障而收敛, 需要一定的时间选择替换路径。 在收敛过程中可能引起发送这两种ICMP差错中的一种, 但是TCP连接并不必被关闭。相反,TCP试图发送引起改差错的数据, 尽管最终有可能会超时。

————————
TCP的重新分组
当TCP超时并重传时,它不一定哟啊重传同样的报文段。 相反,TCP允许进行冲农信分组而发送一个较大的报文段, 这有助于提高性能(当然, 这个较大的报文daunt不能够超过接收方声明的MSS)。 在协议中这是允许的, 因为TCP是使用字节序号而不是使用报文段序号来进行识别它所要发送的数据和进行确认。

有关内容的总结:

  1. TCP 建立过程中中, 一个丢失建立连接的SYN, 随后的重传和超时中怎样使用退避方式
  2. TCP 计算往返时间并使用这些测量结果来维护一个被平滑的RTT估计器和被平滑的均值偏差估计器。 这两个估计器用来计算下一个重传时间。 许多实现对每个窗口仅测量一次RTT。 Karn算法在分组丢失时可以不测量RTT就能够解决重传的二义性问题。
  3. TCP中的算法: 慢启动、拥塞避免、快速重传和快速-恢复。
  4. 多种ICMP差错对TCP连接的影响以及TCP怎么样允许对数据进行重新分组。

几个TCP中的常见的算法的劣迹

TCP定时器: 2mls定时器、 超时定时器、坚持定时器、保活定时器

上一篇下一篇

猜你喜欢

热点阅读