当前位置: 首页 > news >正文

《TCP/IP 详解 卷1:协议》第13章:TCP连接管理

引言

TCP(传输控制协议)是面向连接的单播协议,数据传输前需先建立连接。需要管理多种连接状态(如建立、关闭、重启等)。

连接建立与终止是 TCP 的重要组成部分,也是其与 UDP 最大的区别之一。

TCP连接的建立与终止

一个TCP连接由一个四元组唯一标识:(源IP地址、源端口号、目标IP地址、目标端口号)。连接的每一端可看作一个“套接字(socket)”。

在这里插入图片描述

连接的建立

  1. 客户端 → 服务器

    • 发送 SYN=1,携带客户端初始序列号 ISN(c)
    • 表示“请求建立连接”
    • 报文段1
  2. 服务器 → 客户端

    • 回复 SYN=1ACK=ISN(c)+1
    • 同时发送服务器的初始序列号 ISN(s)
    • 报文段2
  3. 客户端 → 服务器

    • 回复 ACK=ISN(s)+1
    • 报文段3

📌 三次握手的作用:

  • 双方确认连接已建立
  • 交换初始序列号(ISN)
  • 协商连接选项(如窗口大小、时间戳等)

连接的关闭

任何一方都可以主动关闭连接:

  1. 主动关闭方 → 被动关闭方

    • 发送 FIN=1ACK,序列号为 K,确认对方数据序号为 L
    • 表示“我已发送完毕”
    • 报文段1
  2. 被动关闭方 → 主动关闭方

    • 回复 ACK=K+1
    • 表示“你的关闭请求我已收到”
    • 通知应用层
    • 报文段2
  3. 被动关闭方 → 主动关闭方

    • 发送自己的 FIN=1序列号=L
    • 表示“我也发送完毕了”
    • 报文段3
  4. 主动关闭方 → 被动关闭方

    • 回复 ACK=L+1
    • 表示“你的关闭请求我也收到了”
    • 连接彻底关闭
    • 报文段4

✅ 一个连接的完整关闭需要 4 个报文段。

半关闭(Half-close)

TCP允许连接的双向传输独立关闭

  • 一方调用 close() 发送 FIN,表示不再发送,但仍可接收。
  • 另一方仍可继续发送数据,直到也调用 close(),最终完全关闭连接。

🔎 半关闭是一种少见但重要的机制,可用于某些单向传输场景。

在这里插入图片描述

初始序列号

TCP 是一个面向连接的协议,报文段可能乱序或延迟送达。为了解决这些问题,必须为每个连接引入独特的初始序列号(ISN):

  • 防止旧连接残留数据干扰新连接(防 replay)
  • 实现可靠的排序与确认机制

ISN 是一个 32 位的无符号整数,以时间为基础:每4微秒增加1,可视为系统中随时间递增的全局计数器。现代操作系统已广泛采用半随机或加密随机算法生成ISN。

Linux 示例:

  • ISN = 随时间增加的计数器 + 加密偏移
  • 加密偏移基于连接4元组生成的哈希
  • 哈希使用加密散列函数 + 每隔5分钟刷新一次输入种子
  • ISN的高8位可能用于保密或其他目的

Windows 示例:

  • 使用类似 RC4 的伪随机生成器生成 ISN

TCP选项

TCP头部包含了多个选项。选项列表结束(End of Option List,EOL)、无操作(NoOperation,NOP)以及最大段大小(MaximumSegmentSize,MSS)是定义于原始TCP规范中的选项。以下是符合RFC
标准化描述的选项:

在这里插入图片描述

最大段大小选项(MSS:Maximum Segment Size)

MSS 是 TCP 协议中用于指定通信一方“能够接收的最大数据字段大小”(单位:字节),不包括 TCP 和 IP 头部, 目的是避免发送的数据报在路径上被分片。

MSS 选项只能在 TCP 的 SYN 报文段中使用,每一方在建立连接时通过 SYN 报文告诉对方自己的 MSS 限制, 该选项为 16 位整数(最大值 65,535)。

选择确认选项(SACK:Selective Acknowledgment)

TCP 默认采用累计确认(ACK)机制,不能反映乱序数据的接收情况,可能导致不必要的重传。选择确认(SACK)机制能解决这一问题。

在连接建立阶段通过 SYN 或 SYN+ACK 报文中的 SACK-Permitted 选项启用。一旦启用,接收方可以在收到乱序段时,发送 SACK 选项,告知对方哪些数据块已收到。

  • 每个 SACK 块包含一对 32 位的序列号,表示已接收数据的起始与终止范围。
  • 一个 SACK 选项长度为 (8n + 2) 字节,其中 n 是 SACK 块的数量,最大通常为 3 个(假设使用了时间戳选项)。
  • SACK 选项只能在连接建立时协商是否启用,但之后可出现在任意报文中。

窗口缩放选项(Window Scale)

根据 [RFC1323],窗口缩放选项(WSCALE 或 WSOPT)用于将 TCP 的窗口大小从 16 位扩展到最多 30 位,以适应大带宽高延迟网络。

  • TCP 头部中的窗口字段仍为 16 位。
  • 窗口缩放通过一个单字节选项表示,值范围为 0~14。
  • 实际窗口大小 = 通告窗口 × 2^R,其中 R 是对方通告的缩放因子。

窗口缩放选项只能出现在 SYN 报文中,连接建立后不能更改。双方需在各自的 SYN 报文中发送此选项,方可在对应方向启用。若主动方发送了窗口缩放,但未收到响应方的对应选项,则双方默认比例为 0(即不缩放)。每个方向可以有不同的比例因子。

时间戳选项与防回绕序列号(TSopt & PAWS)

每个 TCP 报文段中添加两个 4 字节字段:

  • TSval:当前时间戳值(发送方生成)
  • TSecr:回显时间戳值(对方上次发送的 TSval)

用于估算TCP 往返时间(RTT),帮助设置重传超时(RTO)。报文头部增加 10 字节(2 字节类型/长度 + 8 字节数据)。不要求主机间时钟同步,只需保证 TSval 单调递增。

  • 精准 RTT 估算(配合 RTO 算法,如 RFC6298)
  • 更频繁、准确地采样 RTT,提高传输效率
  • 搭配重传机制更智能地判断丢包

TCP 序列号为 32 位,可能在高速传输时“回绕”。时间戳用于检测并丢弃旧报文段。

规则: 接收方仅接受时间戳 ≥ 上次接收的有效时间戳的报文段。

在这里插入图片描述
时间戳选项不仅增强 RTT 估算能力,还提供了 防止旧报文干扰新连接的机制(PAWS),是 TCP 高速传输场景中重要的可靠性选项。

用户超时选项(User Timeout Option, UTO)

用户超时(USER_TIMEOUT)定义为 TCP 发送方愿意等待未确认数据的最长时间。UTO 选项允许通信双方在 TCP 报文中显式告知对方自己的超时设置,目的是增强容错能力,例如容忍临时的连接中断。

USER_TIMEOUT = min(U_LIMIT, max(ADV_UTO, REMOTE_UTO, L_LIMIT))
  • ADV_UTO: 本地希望的超时
  • REMOTE_UTO: 远端希望的超时
  • U_LIMIT: 本地允许的最大值
  • L_LIMIT: 本地允许的最小值(建议 ≥ 100 秒)

报文携带 UTO 的时机:

  • 连接建立时的 SYN 报文
  • 第一个非 SYN 报文段
  • USER_TIMEOUT 数值发生变化时

认证选项(TCP Authentication Option, TCP-AO)

TCP-AO 是 TCP 协议的一个安全扩展选项,用于认证每个 TCP 报文段的真实性。它是为增强和替代早期的 TCP-MD5 机制([RFC2385])而设计的。

  • 共享密钥机制:通信双方必须预先协商出一组共享的密钥。
  • 加密散列算法(见第18章):对每个 TCP 报文段进行认证值计算。
  • 带内信令:用于指示认证参数(如密钥)是否发生变化。

发送方:使用共享密钥生成通信密钥,使用该通信密钥对报文段进行加密散列计算,将认证值附加到报文段中。

接收方:使用相同密钥进行散列验证,检查报文段是否被篡改。

TCP 的路径最大传输单元发现(PMTUD)

路径最大传输单元(Path MTU, PMTU):两主机间路径上所有链路的最小 MTU 值。

通过路径最大传输单元发现(PMTUD),TCP 能避免 IP 分片,提高传输效率。

TCP 中的 PMTUD 过程

  1. 连接建立时

    • TCP 选择初始的发送方最大段大小(SMSS):
      • 取本地接口 MTU 与对方声明的 MSS 中的较小值;
      • 若对方未声明 MSS,则默认为 536 字节(较少见)。
    • 设置 IPv4 报文中的 DF(Don’t Fragment)位,避免分片。
  2. 处理 PTB(Packet Too Big)消息

    • 若收到 PTB 或 ICMP “需要分片但 DF 已设置” 消息:
      • 减小段大小并重新发送。
      • 若包含推荐的下一跳 MTU,则将其减去 IP + TCP 头部长度作为新 MSS。
      • 若无推荐值,可采用二分法尝试。
  3. 路径两端方向可能不同

    • 每个方向的 PMTU 应独立处理。

黑洞问题

原因:中间设备(如防火墙/NAT)阻止 ICMP 消息转发;

表现:连接建立正常,但大数据包始终重传失败;

解决方式

  • TCP 实现尝试使用较小报文段;
  • 启用黑洞探测机制(重传失败后自动降低 MSS);
  • 建议部署者配置设备允许 ICMP PTB 消息通过。

TCP状态转换

在一个连接的不同阶段需要发送各种类型的报文段。这些决定TCP应该做什么的规则其实是由TCP所属的状态决定的。当前的状态会在各种触发条件下发生改变,例如传输或接收到的报文段、计时器超时、应用程序的读写操作,以及来自其他层的信息。这些规则可以概括为TCP的状态转换图。

TCP状态转换图

在这里插入图片描述

TCP 从 CLOSED 状态启动。

  • 根据连接的发起方式:
    • 主动打开:转为 SYN_SENT
    • 被动打开:转为 LISTEN

主动打开方(客户端)CLOSEDSYN_SENTESTABLISHED

被动打开方(服务器)CLOSEDLISTENSYN_RCVDESTABLISHED

主动关闭方ESTABLISHEDFIN_WAIT_1FIN_WAIT_2TIME_WAITCLOSED

被动关闭方ESTABLISHEDCLOSE_WAITLAST_ACKCLOSED

  • CLOSING:当通信双方同时发送 FIN 时出现。
  • SYN_RCVDLISTEN:仅当该状态来自 LISTEN 且收到 RST 报文时才会回退。
  • LISTENSYN_SENT:合法但很少使用,不被 Berkeley 套接字支持。

主动关闭状态集合

  • FIN_WAIT_1
  • FIN_WAIT_2
  • TIME_WAIT

被动关闭状态集合

  • CLOSE_WAIT
  • LAST_ACK

在这里插入图片描述

TIME_WAIT 状态

TIME_WAIT 状态也称为 2MSL 等待状态。在该状态中,TCP 将等待两倍于最大段生存期(MSL, Maximum Segment Lifetime)的时间,也称加倍等待。

每个实现必须指定一个 MSL 值,它表示报文段在网络中被允许存在的最长时间。TIME_WAIT 的用途:

  1. 保证最终 ACK 能被对方接收

当 TCP 执行主动关闭并发送最后一个 ACK 后,需要等待 2MSL,以便对方未收到 ACK 时重发 FIN,我们可以重新发送 ACK

注意:ACK 本身不消耗序列号,不会被 TCP 重传。但对方的 FIN 消耗序列号,会被重传,因此必须准备再次发送 ACK

  1. 避免连接混淆

处于 TIME_WAIT 的连接不能立即被复用,防止旧连接的延迟报文被误判为新连接的内容。其定义了一条不可重用的四元组:(客户端 IP、端口、服务端 IP、端口)

如果新连接使用了相同四元组,必须满足以下至少一个条件才能避免混淆:

  • 已过 2MSL 等待时间;
  • 新连接初始序列号明显高于旧连接;

客户端主动关闭后通常进入 TIME_WAIT。如果立刻重启客户端,它无法使用相同本地端口。一般不会有异常情况,因为客户端常用临时端口,并不关心具体数值,且这些端口通常由操作系统自动分配,一般不会重复。

静默时间的概念

在本地与远端的 IP 地址与端口号完全相同的情况下,2MSL 状态可以防止新的连接误将前一连接的延迟报文段当作自己的数据。

然而,这种保护机制依赖于参与 TIME_WAIT 状态的主机在此期间未崩溃或重启。如果某台主机在 MSL 时间内崩溃并重启,并继续使用相同的 IP 与端口号,则可能出现以下风险:

  • 重启后的新连接可能接收到旧连接中的延迟报文段;
  • TCP 将这些旧数据错误地当作新连接的一部分;
  • 即使新连接使用了不同的初始序列号,这些报文也可能通过校验。

为了解决这个问题,[RFC0793] 要求:

在主机崩溃或重启之后,应等待 至少一个 MSL 的时间 再创建新连接,该等待时间称为“静默时间(quiet time)”。

尽管有此要求,但实际中:

  • 大多数系统在崩溃重启后需要的时间远超过 MSL,所以该问题 较少发生
  • 现代应用程序普遍使用 校验和、加密 等机制进行数据校验,能够检测出错误数据;

因此,静默时间机制在理论上仍然重要,但在实际中其必要性已被系统恢复延迟与上层校验机制部分取代。

FIN_WAIT_2 状态

当 TCP 连接的一端已经发送 FIN 并收到了对方的确认,此时该端会进入 FIN_WAIT_2 状态。此时的含义是:

  • 本端已经完成发送数据
  • 等待对方发送自己的 FIN,以完成连接的关闭。

如果出现半关闭(即本端关闭了发送方向,但仍期望接收数据),则连接会持续处于 FIN_WAIT_2 状态,直到:

  • 对方的应用程序完成关闭;
  • 对方发送 FIN 报文段;
  • 本端收到该 FIN,并进入 TIME_WAIT 状态。

如果对方迟迟不关闭(即未发送 FIN),那么连接可能永远停留在 FIN_WAIT_2,从而造成资源泄漏。对应地,对方可能永远处于 CLOSE_WAIT 状态,直到应用层决定关闭。为避免无限等待,大多数实现提供超时机制。

重置报文段

TCP头部有RST位字段。将该字段置位的报文段称为“重置报文段”或简称“重置”。当TCP发现一个到达的报文段对于相关连接(由该报文段的TCP和IP头部四元组指定的连接)是不正确的,通常会发送一个重置报文段。

重置报文段一般会导致TCP连接的快速拆卸。下面通过具体场景说明重置报文段的作用。

针对不存在端口的连接请求

当连接请求到达本地但目的端口没有相关进程侦听时,会产生重置报文段。这与之前“连接被拒绝”的错误消息对应。UDP协议对此类情况采用ICMP目的地不可达(端口不可达)消息,而TCP协议则使用重置报文段完成类似功能。

在这里插入图片描述

重点分析重置报文段(第2个报文段)中的序列号和ACK号。因为到达的SYN报文段未设置ACK位,重置报文段的序列号为0,而ACK号为收到的初始序列号加上该报文段中的数据长度。虽然报文中无数据,SYN位逻辑上占用一个序列号空间,所以ACK号等于初始序列号 + 0 + 1。

终止一条连接

TCP连接的正常终止方法是通信一方发送一个FIN报文段,这种方式称为有序释放,保证之前所有排队数据都已发送,避免数据丢失。

也可以通过发送重置(RST)报文段来替代FIN终止连接,这种方式称为终止释放。

使用重置报文段终止连接具有两个特性:

  • 任何待发送的数据都会被立即丢弃,连接终止后发送RST报文;
  • 接收RST的一方能明确知道连接是被非正常终止而非正常关闭。为了支持这种终止方式,套接字API提供了通过将“逗留于关闭”(SO_LINGER)选项设置为0实现的功能,意味着不会在关闭时等待数据确认到达对端。

在这里插入图片描述

总结来看,重置报文段可作为一种快速断开TCP连接的机制,常用于异常终止场景、

半开连接

当一端在未通知另一端的情况下关闭或崩溃,TCP连接进入半开状态。此时,正常工作的那一端无法检测到对端已失效,只要不发送数据,连接仍维持ESTABLISHED状态。

常见原因包括主机突然断电而非正常关机。例如,远程登录客户端关闭电源后,服务器仍认为连接存在,直到新会话启动,导致服务器存在大量半开连接。TCP的keepalive机制(第17章介绍)可用于检测此类失效。

时间等待错误

TIME_WAIT状态设计用于确保关闭连接后,任何滞留的数据报文都能被丢弃。此期间,TCP通常不执行操作,只需维持状态直到2MSL计时结束。

然而,如果TIME_WAIT期间收到来自该连接的报文,尤其是RST报文,可能导致TIME_WAIT状态被破坏,连接提前关闭,这称为时间等待错误(TIME_WAIT Assassination)

在这里插入图片描述
客户端(主动关闭方)完成关闭后进入TIME_WAIT,服务器(被动关闭方)连接关闭并清理状态。若客户端接收到一个序号和ACK号都很旧的数据报文,客户端会回复带最新序号和ACK号的ACK报文。服务器此时因无连接状态,会返回RST报文,客户端接收后错误地提前关闭连接。

解决方案:多数系统在TIME_WAIT状态时忽略RST报文,防止连接被误破坏,确保可靠关闭过程。

相关文章:

  • 自建站和独立站一样吗网络营销策划书的结构是什么
  • wordpress升级后出错aso关键词优化工具
  • 郑州网站推广优化公司如何创建个人网页
  • 安徽安搜做的网站怎么样百度小说网
  • 烟台城发建设集团网站谷歌怎么推广自己的网站
  • 衡水网站建手机百度正式版
  • java-SpringBoot框架开发计算器网页端编程练习项目【web版】
  • 马克思主义基本原理知识笔记
  • MediaMarktSaturn EDI 对接指南:欧洲零售卖场的数字化协同范例
  • 虚幻基础:插槽
  • C++面试6——类和结构体的区别和使用场景
  • 零基础学习RabbitMQ(3)--核心概念
  • 打包上传到Linux部署并启动
  • C++ string类的操作
  • FFMPEG常用函数
  • 应用层协议 HTTP
  • 618风控战升级,瑞数信息“动态安全+AI”利剑出鞘
  • 无人机航电系统之语音通信技术篇
  • elk+filebeat收集springboot项目日志
  • 开疆智能CCLinkIE转ModbusTCP网关连接川崎机器人配置案例
  • 桥头守望者
  • WRF模式与Python融合技术在多领域中的应用及精美绘图;Python助力WRF自动化运行、WRF模式前后处理
  • Android Navigation 架构
  • 从虚拟机角度解释python3相对导入问题(下)
  • 创始人IP打造:知识付费领域破局的核心方法论
  • 服务器安装指南