计网笔记-传输层(二)TCP

发布于:2025-05-15 ⋅ 阅读:(7) ⋅ 点赞:(0)

TCP核心特性: 面向连接的、可靠的、字节流、全双工、点对点。

一、TCP连接:不仅仅是握手

  1. 面向连接 (Connection-Oriented):

    • 握手 (Handshake): 在数据传输前,通信双方(客户端和服务器)必须通过“三次握手”建立连接。
      • 目的:
        • 交换初始序号 (ISN)。
        • 同步双方状态,如MSS、窗口缩放选项等。
        • 分配必要的内核资源(缓存、变量)。
      • 过程简述:
        1. 客户端 SYN(seq=client_isn) -> 服务器
        2. 服务器 SYN(seq=server_isn), ACK(ack=client_isn+1) -> 客户端
        3. 客户端 ACK(ack=server_isn+1) -> 服务器 (此报文可携带数据)
    • 逻辑连接: TCP连接是端到端系统TCP程序中的状态,中间网络设备(路由器)不感知或维护TCP连接状态,它们只处理IP数据报。
    • 状态变量: 连接双方都会初始化和维护一系列状态变量,如序号、确认号、窗口大小、RTT估计等。
  2. 全双工 (Full-Duplex): 数据可以在两个方向上同时独立传输。每个方向都有自己的序号和确认号。

  3. 点对点 (Point-to-Point): 一条TCP连接只涉及两个端点,不支持多播或广播。

二、TCP报文段结构 (Segment Structure)

一个TCP报文段包含首部 (Header) 和数据 (Data Payload)。
image.png

image.png

  • 源端口号 (Source Port) 和 目标端口号 (Destination Port) (各16位):
    • 用于在端系统中实现多路复用 (Multiplexing) 和多路分解 (Demultiplexing),将数据导向正确的应用进程。
  • 序号 (Sequence Number) (32位):
    • 标识该报文段数据部分第一个字节在整个字节流中的位置。
    • TCP将数据视为一个无结构的、有序的字节流。
    • ISN (Initial Sequence Number) 是随机选择的,以增加安全性。
  • 确认号 (Acknowledgment Number) (32位):
    • 期望从对方接收的下一个字节的序号。
    • 只有当ACK标志位为1时才有效。
    • TCP提供累计确认 (Cumulative Acknowledgment):确认号y表示序号小于y的所有字节都已正确按序接收。TCP只确认该流中至第一个丢失字节为止的字节
  • 首部长度 (Header Length / Data Offset) (4位):
    • 表示TCP首部的长度,以32位字(4字节)为单位。
    • 最小值为5(20字节,无选项),最大值为15(60字节)。
  • 保留 (Reserved) (通常为6位,RFC 3168后有调整用于ECN):
    • 未来使用,必须为0。
  • 标志位 (Flags) (通常为6位,加上ECN后为8位):
    • URG: 紧急指针字段有效。
    • ACK: 确认号字段有效。
    • PSH: 推送功能,接收方应尽快将数据交给应用层。(实践中少用)
    • RST: 重置连接,通常在出现错误或异常时使用。
    • SYN: 同步序号,用于发起连接。
    • FIN: 终止连接,发送方已无数据发送。
    • CWR (Congestion Window Reduced) 和 ECE (ECN-Echo): 用于明确拥塞通告 (ECN)。
  • 接收窗口 (Receive Window / rwnd) (16位):
    • 用于流量控制。
    • 表示接收方当前愿意接收的字节数量(可用的缓存空间)。
    • 单位是字节。可通过窗口缩放选项扩展。
  • 校验和 (Checksum) (16位):
    • 对TCP首部、TCP数据以及一个伪首部(包含源IP、目标IP、协议号、TCP长度)进行计算,用于差错检测。
  • 紧急指针 (Urgent Pointer) (16位):
    • URG标志位为1时有效,指向紧急数据最后一个字节的下一个字节的序号。(实践中少用)
  • 选项 (Options) (可变长度,最多40字节):
    • 目的: 扩展TCP功能,协商参数。
    • 常见选项:
      • MSS (Maximum Segment Size): 在SYN报文段中协商,通常基于路径MTU设置,避免IP分片。
        • image.png
      • Window Scale (RFC 7323): 允许接收窗口rwnd超过65535字节,用于高带宽延迟积网络。
      • SACK (Selective Acknowledgment, RFC 2018, 2883): 允许接收方指明已收到的失序报文段,提高重传效率。
      • Timestamps (RFC 7323):
        • RTTM (Round-Trip Time Measurement): 更精确的RTT测量。
        • PAWS (Protection Against Wrapped Sequence numbers): 防止序号回绕问题。
      • NOP (No-Operation): 用于选项字段的字节对齐。
  • 数据 (Data Payload): 应用层数据。其长度受MSS限制。

三、可靠数据传输 (Reliable Data Transfer)

TCP使用多种机制确保数据可靠、按序到达:

  1. 序号和确认号机制:
    • 累计确认: 如前所述。
    • 失序处理: 接收方通常会缓存失序到达的报文段,等待缺失的报文段填补间隔。

序号建立在传送的字节流之上,而不是建立在传送的报文段的序列之上。因此==一个报文段的序号是该报文段首字节的字节流编号。==引用https://kiprey.github.io/2021/05/cnatda-1/#4-%E9%9D%A2%E5%90%91%E8%BF%9E%E6%8E%A5%E7%9A%84%E8%BF%90%E8%BE%93%EF%BC%9ATCP
image.png

  • 举例说明:
    image.png

以下是交互过程的分解说明:

1)  **用户在主机 A 上输入字符 'C':**
    *   主机 A 向主机 B 发送一个包含字符 'C' 的 TCP 报文段。
    *   **报文段详情 (A -> B):**
        *   `Seq=42`: 这是主机 A 发送的(第一个也是唯一一个)数据字节 'C' 的序号。这暗示主机 A 在此流中已经发送了42个字节,或者其初始序号 (ISN) 是41。
        *   `ACK=79`: 这是主机 A 的确认号,表明它期望从主机 B 收到的下一个字节的序号是79。
        *   `data='C'`: 报文段的载荷是单个字符 'C'。

2)  **主机 B 收到 'C' 并将其回显:**
    *   主机 B 上的 Telnet 服务器通常会将字符回显给客户端(主机 A)。
    *   主机 B 首先确认收到了 'C',然后将 'C' 发送回去。
    *   **报文段详情 (B -> A):**
        *   `Seq=79`: 这是主机 B 发送的字符 'C' 的序号。这与主机 A 之前发送的 ACK(ACK=79)相吻合。
        *   `ACK=43`: 主机 B 确认收到了来自主机 A 的数据。因为 'C' 是1个字节且起始序号是42,所以期望从主机 A 收到的下一个字节是 42 + 1 = 43。
        *   `data='C'`: 载荷是回显的字符 'C'。

3)  **主机 A 收到回显的 'C' 并进行确认:**
    *   主机 A 收到了主机 B 回显的 'C'。
    *   主机 A 向主机 B 发回一个确认。如果用户没有输入其他内容,这个报文段可能不包含新的数据。
    *   **报文段详情 (A -> B):**
        *   `Seq=43`: 这是主机 A 当前的序号。因为它之前发送到字节42 ('C'),所以它的下一个数据字节将从43开始。即使此报文段中没有发送新数据,序号也必须是有效的。
        *   `ACK=80`: 主机 A 确认收到了来自主机 B 的回显 'C'。因为主机 B 以序号79发送了 'C'(且 'C' 是1个字节),所以期望从主机 B 收到的下一个字节是 79 + 1 = 80。
  1. 超时重传机制 (Retransmission Timeout / RTO):

    • TCP使用超时/重传机制来处理报文段的丢失问题。超时时间间隔长度必须大于该连接的往返时间(RTT),即从一个报文段发出到它被确认的时间,否则会造成不必要的重传。
    • RTT估计:
      • SampleRTT: 从报文段发出到收到其确认之间的时间。
      • E s t i m a t e d R T T = ( 1 − α ) ∗ E s t i m a t e d R T T + α ∗ S a m p l e R T T ( α ≈ 0.125 ) EstimatedRTT = (1-α) * EstimatedRTT + α * SampleRTT (α ≈ 0.125) EstimatedRTT=(1α)EstimatedRTT+αSampleRTT(α0.125)
      • D e v R T T = ( 1 − β ) ∗ D e v R T T + β ∗ ∣ S a m p l e R T T − E s t i m a t e d R T T ∣ DevRTT = (1-β) * DevRTT + β * |SampleRTT - EstimatedRTT| DevRTT=(1β)DevRTT+βSampleRTTEstimatedRTT (β ≈ 0.25)
      • T i m e o u t I n t e r v a l ( R T O ) = E s t i m a t e d R T T + 4 ∗ D e v R T T TimeoutInterval (RTO) = EstimatedRTT + 4 * DevRTT TimeoutInterval(RTO)=EstimatedRTT+4DevRTT
      • 初始RTO通常为1秒。
      • Karn算法: 不对重传报文段的ACK进行SampleRTT采样,避免重传歧义。
    • 超时事件: 若在RTO内未收到确认,则认为报文段丢失,进行重传。
    • 超时间隔加倍 (Exponential Backoff): 每次超时重传后,RTO会翻倍,以应对持续的网络拥塞或长时间的延迟。而不是由EstimatedRTT和DevRTT推断出的值。
  2. 快速重传 (Fast Retransmit):
    超时重传的周期相对较长,可以用快速重传来解决超时重发的时间等待问题。
    不以时间为驱动,而以数据为驱动进行重传

    • 当发送方收到3个或更多针对同一数据的冗余ACK (Duplicate ACKs) 时,不等超时定时器到期就立即重传该数据之后的报文段。
    • 原理: 冗余ACK表明接收方收到了后续的报文段,但之前的某个报文段丢失了。
  3. 选择确认 (SACK - Selective Acknowledgment):
    快速重传解决了超时问题,还有一个问题就是重传的时候是重传一个还是重传所有问题,所以引出了SACK.
    小林coding

    • 作为TCP选项,允许接收方明确告知发送方哪些不连续的数据块已收到。
    • 发送方可以据此只重传真正丢失的报文段,而不是从第一个丢失点开始的所有数据。
      image.png
  4. 校验和 (Checksum): 用于检测报文段在传输过程中是否发生比特错误。

TCP的差错恢复机制可以看作是 GBN (Go-Back-N) 和 SR (Selective Repeat) 协议的混合体。 基础是累计确认(类似GBN),但通过缓存失序报文段和SACK选项(类似SR)来提高效率。

四、流量控制 (Flow Control)

  • 目的: 防止发送方发送数据过快,超出接收方处理能力,导致接收方缓存溢出。
  • 机制: 使用接收窗口 (rwnd)
    • 接收方在其发送给发送方的报文段的rwnd字段中通告其当前可用的缓存空间。
    • 发送方维护的有效窗口 (Effective Window) = min(cwnd, rwnd) - (LastByteSent - LastByteAcked)
    • 发送方发送的数据量不能超过接收方的rwnd
  • 零窗口问题与持续探测:
    • rwnd=0时,接收方缓存已满。
    • 若此时接收方没有数据要发给发送方,发送方可能不知道何时rwnd变非零。
    • TCP规范要求: 当接收窗口为0时,发送方会周期性地发送只包含1字节数据的探测报文段 (Persist Timer)。接收方必须确认这些探测报文,并在确认中包含当前的rwnd值。

五、拥塞控制 (Congestion Control)

  • image.png

  • 目的: 防止过多数据注入网络,导致网络拥塞(路由器缓存溢出、高延迟、丢包)。

  • 机制: TCP发送方通过维护一个拥塞窗口 (cwnd) 来动态调整发送速率。

    • 实际发送速率受限于 min(cwnd, rwnd) / RTT
  • 拥塞感知:

    • 丢包事件 (Packet Loss): 主要的拥塞信号。
      • 超时 (Timeout)
      • 3个冗余ACK (Fast Retransmit)
    • ECN (Explicit Congestion Notification): 网络辅助机制,路由器可以在IP头中标记拥塞,接收方通过TCP头反馈给发送方。
  • TCP拥塞控制算法 (核心思想:AIMD - Additive Increase, Multiplicative Decrease):

  • image.png

    1. 慢启动 (Slow Start):

      • 初始 cwnd = 1 MSS (或2-4 MSS,根据RFC)。
      • 每收到一个ACK,cwnd增加1 MSS (指数增长,每RTT翻倍)。
      • 目的: 快速探测网络可用带宽。
      • cwnd达到慢启动阈值 (ssthresh) 时,或发生丢包时,转换状态。
    2. 拥塞避免 (Congestion Avoidance):

      • cwnd >= ssthresh时进入。
      • cwnd每RTT增加1 MSS (线性增长)。
      • 目的: 谨慎增加发送速率,避免迅速再次拥塞。
    3. 拥塞处理 (对丢包事件的反应):

      • 超时丢包 (TCP Tahoe/Reno):
        • ssthresh = cwnd / 2
        • cwnd = 1 MSS
        • 重新进入慢启动。
      • 3个冗余ACK (TCP Reno):
        • ssthresh = cwnd / 2
        • cwnd = ssthresh + 3 MSS (快速重传后,inflate窗口以应对冗余ACK)
        • 进入快速恢复 (Fast Recovery) 状态。
    4. 快速恢复 (Fast Recovery - TCP Reno):
      图片引用自:小林coding

      • image.png
      • 每收到一个额外的冗余ACK,cwnd增加1 MSS (继续inflate)。
      • 当收到对丢失报文段的新ACK时:
        • cwnd = ssthresh
        • 进入拥塞避免状态。
      • 若发生超时,则按超时丢包处理(cwnd=1 MSS,进入慢启动)。
  • ssthresh (Slow Start Threshold):

    • 初始值可以很高。
    • 发生拥塞时,通常设置为当前cwnd的一半。
  • 拥塞控制算法的演进:

    • Tahoe: 早期版本,任何丢包都导致cwnd=1
    • Reno: 引入快速重传和快速恢复。
    • NewReno: 改进Reno对一个窗口内多个丢包的处理。
    • SACK-TCP: 结合SACK选项,更精确重传,改进恢复。
    • CUBIC: Linux默认,基于三次函数,高BDP网络友好。
    • BBR (Bottleneck Bandwidth and Round-trip propagation time): Google开发,不依赖丢包,基于带宽和RTT估计。
  • 公平性: 理想情况下,多个TCP连接共享瓶颈链路时,应能公平分配带宽。但UDP等无拥塞控制的协议可能挤占TCP流量。

六、TCP连接管理 (Connection Management)

  1. 三次握手 (Three-Way Handshake): 建立连接。

    • (已在第一部分详述)
    • SYN洪泛攻击 (SYN Flood Attack): 攻击者发送大量SYN请求但不完成握手,耗尽服务器资源。防御机制包括SYN Cookies、防火墙限制等。
  2. 四次挥手 (Four-Way Handshake): 拆除连接。

    • TCP连接是全双工的,每个方向的关闭都是独立的。
    • 过程简述 (A主动关闭,B被动关闭):
      1. A FIN(seq=x) -> B (A表示不再发送数据)
      2. B ACK(ack=x+1) -> A (B确认收到A的FIN)
      • 此时B可能仍有数据要发送给A,连接处于半关闭 (Half-Close) 状态。
      1. B FIN(seq=y) -> A (B表示也不再发送数据)
      2. A ACK(ack=y+1) -> B (A确认收到B的FIN)
    • 状态机与TIME_WAIT状态:
      • 主动关闭方在发送最后一个ACK后会进入TIME_WAIT状态。
      • 目的:
        1. 确保最后一个ACK能到达对方(若丢失,对方会重传FIN,TIME_WAIT状态的A可以重发ACK)。
        2. 确保网络中所有与此连接相关的旧的、延迟的报文段都已消失,防止它们干扰后续使用相同四元组(源IP、源端口、目标IP、目标端口)的新连接。持续时间通常为 2*MSL (Maximum Segment Lifetime)。

七、其他重要机制与概念

  1. Nagle算法 (RFC 896):

    • 目的: 减少网络中的小报文段("糊涂窗口综合症"的一种表现),提高网络效率。
    • 机制: 如果有已发送但未确认的数据,并且新产生的数据小于MSS,则缓存这些小数据,直到收到ACK或积累到MSS再发送。
    • 影响: 可能引入小延迟,对某些交互式应用(如Telnet、SSH按键回显)不利,可禁用 (TCP_NODELAY socket选项)。
  2. 延迟ACK (Delayed ACKs):

    • 目的: 减少纯ACK报文的数量,提高效率。
    • 机制: 接收方不必为每个收到的数据段立即发送ACK,可以等待一小段时间(如200ms)或等待有数据要捎带时再发送。
    • 影响: 可能引入小延迟。与Nagle算法同时作用时,可能导致更明显的延迟。
  3. 字节流服务 (Byte-Stream Service):

    • TCP向上层应用提供的是一个无边界的、有序的字节流。应用层写入的数据可能会被TCP分割成多个报文段,或者多个小写入可能会被TCP合并成一个报文段。应用层需要自己处理消息边界。
  4. 最大报文段长度 (MSS - Maximum Segment Size):

    • TCP报文段中数据部分的最大长度。
    • 通常根据路径MTU(最大传输单元)减去TCP/IP首部长度来设置,以避免IP层分片。
    • 在三次握手期间通过TCP选项协商。
  5. TCP状态机 (TCP State Machine):

    • 描述TCP连接从建立到关闭过程中的各种状态及其转换。
    • 关键状态:CLOSED, LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT, LAST_ACK, TIME_WAIT

八、TCP的局限性与未来

  1. 队头阻塞 (Head-of-Line Blocking): 在单个TCP连接中,一个报文段的丢失会阻塞后续所有报文段的交付,即使它们已正确到达。
  2. 连接建立延迟: 三次握手至少引入1个RTT的延迟。
  3. 对某些应用不理想: 实时音视频、游戏等对低延迟要求高、能容忍少量丢包的应用,可能更适合UDP。
  4. 移动网络和高丢包环境下的表现: 传统的TCP拥塞控制将丢包视为拥塞,可能在无线等非拥塞丢包环境下表现不佳。
  5. 演进方向 (例如QUIC):
    • QUIC运行在UDP之上,解决了TCP的一些问题:
      • 多路复用流,避免队头阻塞。
      • 更快的连接建立 (0-RTT或1-RTT)。
      • 集成的TLS加密。
      • 独立的流级拥塞控制。

滑动窗口直接看小林coding的写的很清楚了,参考以下图例,cs144 lab0、lab1
在这里插入图片描述

参考

  1. 自顶向下第八版
  2. 小林coding
  3. kiprey.github.io