重读TCP 协议

拖延症晚期患者,终于在周末的尾巴开始写这篇本来上周就应该总结出来的文章了……。

1. 基本概念

大部分介绍 tcp 协议的开头都是, tcp 协议是一种面向连接的、可靠的、基于字节流的传输层协议。讲真的就是这么单纯的记住这个概念,在实践中并没有什么具体用处,毕竟工作和考试不一样……。为了更深刻的理解这个协议,让我们先拆解下概念要点:

  • 传输层协议,什么是传输层呢,为什么需要抽象传输层的概念呢?

    为了理解这个问题,我们必须从最最底层的物理层、数据链路层、网络层先说起,然后才能够真正理解传输层存在的意义,各层次之间的关系如下图:

    在这里插入图片描述

  • 面向连接的、可靠的、基于字节流怎么理解?

    传输层控制的是端到端的传输,即一个程序到另一个程序之间的数据传输。为了方便继续,假设 A B两个程序。

    • 面向连接的

      tcp 的连接建立需要三次握手的过程,三次握手可以理解成 A、B 两个程序交换端口号的过程,端口交换以后,以后所有A、B程序之间每次数据传输,都必须正确的指明源目的端口号,这样我们就在物理层 0/1 电信号传输的基础上抽象出连接的概念

    • 可靠的

      为了保证发送的数据能够正确的到达对端,tcp 协议提供了超时重传的机制。(ps IP 层的分片可能丢失,但是 IP 层并没有超时重传机制,所以 tcp 要确保可靠性,只能提供超时重传的机制

    • 基于字节流

      程序对于数据的发送和接收是没有边界的,所以直接基于 tcp 传输数据会产生「粘包」问题。

2. 那些你不知道的事?

理解完上面的基础概念,你就真的懂 tcp 协议了吗?让我们问几个问题测试下

2.1 TIME_WAIT 状态存在的原因是什么?

很简单,笔者手边的书就清楚的写着这么两条

  • 可靠的终止 TCP 连接;
  • 保证让迟来的 TCP 连接报文有足够的时间被识别和丢弃;

曾经我也是这么回答的,但是这个回答明显是经不起推敲的,啥叫可靠的终止 TCP 连接,为啥没有 TIME_WAIT 状态就不可靠了,咦,你是不是没想过?

其实这个问题的根本原因是每次建立连接的序列号都是随机的,并且这个序列号是 32 的,会发生回绕。我们知道,IP 数据报最多存活 MSL(报文最大生存时间),那么就有可能发生下面的情况:

在这里插入图片描述

2.2 超时时间如何计算与管理

2.2.1 超时时间计算:

RTT 时间指的是一个 tcp 数据分段的往返时间。但是路由是动态的,并且路由器有可能会缓存或者丢弃任何数据,因此 RTT 时间也必须动态测量。 So,怎么测量,多次测量取算术平均值?明显是不符合要求的,假设两次测量的值是 1 和 99 ,平均值则为 50 ,则会有以下的问题:

  • 对于 1 来说,这个值太大了,本该立刻重传但是延迟好久才重传,导致数据延迟过大
  • 对于 99 来说,这个值太小了,会大量重传已经正确确认但是迟到的 tcp 分段,导致过度重传

因此,除了考虑每两次测量值的偏差之外,其变化率也应该考虑在内,如果变化率过大,则通过以变化率为自变量的函数为主计算RTT,反之如果变化率很小,则取测量平均值。

2.2.2 超时时间的管理:

超时的设置是基于每个 tcp 分段的还是基于每个 tcp 连接的呢?明显这么问的话,肯定就是基于 tcp 连接的,但是基于 tcp 连接有什么好处吗?

基于 tcp 连接设置超时能够减少内存开销和调度开销。

设计计时器的原则——每一个报文在超过最近 RTT 测量的时间收不到确认都必须可超时,因此RFC2988 定义一套很简单的原则:

  1. 发送TCP分段时,如果还没有重传定时器开启,那么开启它。

  2. 发送TCP分段时,如果已经有重传定时器开启,不再开启它。

  3. 收到一个非冗余ACK时,如果有数据在传输中,重置重传定时器。

  4. 收到一个非冗余ACK时,如果没有数据在传输中,则关闭重传定时器。

只要 1,2 存在就能够满足上述设计计时器的原则,为什么还要增加后面的两条呢?

  • 先看第 4 条,本着节能减排的原则,你都没有数据传输着,你还开什么定时器,不是浪费资源嘛……

  • 再看第 3 条,假设再重传定时器到期前,发送了一些数据,这样在定时器到期后,除了很早发送的数据能收到 ACK 外,其它稍晚些发送的数据的 ACK 都将不会到来,这会导致数据被重传。再有了第 3 条以后,只要有分段的 ACK 到来,则重置定时器。

    这么直接重置定时器真的合适嘛?

    没什么不合适的,大多数正常情况下,从数据的发出到 ACK 的到来这段时间以及计算得到的 RTT 以及重传定时器超时的时间这三者相差并不大,一个 ACK 到来后重置定时器可以保护后发的数据不被过早重传。

本来呢,笔者是想把流量控制这部分也写完的,但是鉴于最近不适合熬夜以及要「认真工作,快乐生活」,那我就先留个坑吧,不过 tcp 流量控制部分很多设计还是很值得学习。

3. 参考资料

Guess you like

Origin blog.csdn.net/phantom_111/article/details/102655409