《深入理解 RFC 793:传输控制协议(TCP)》

📅 2026/7/6 15:32:59 👁️ 阅读次数 📝 编程学习
《深入理解 RFC 793:传输控制协议(TCP)》

本文基于 RFC 793 原始规范整理,所有内容均来自文档原文,无外部延伸知识,适合网络开发、运维及协议学习者阅读。


一、文档速览:RFC 793 基本信息

基础属性

  • RFC 编号:793
  • 完整标题TRANSMISSION CONTROL PROTOCOL(传输控制协议),副标题为DARPA INTERNET PROGRAM PROTOCOL SPECIFICATION(DARPA 互联网项目协议规范)
  • 协议状态:文档明确定义为美国国防部(DoD)标准传输控制协议,基于此前 9 版 ARPA TCP 规范制定
  • 发布日期:1981 年 9 月
  • 替代关系:替换 RFC 761,及此前 9 版 ARPA TCP 相关规范(对应 IEN 编号:129、124、112、81、55、44、40、27、21、5);当前文档未提及被后续 RFC 更新或废弃的信息

核心目标

TCP 的核心设计目标是:在不可靠的分组交换互联网络中,为不同主机上的进程提供面向连接、可靠、有序、全双工的端到端通信服务;同时完整定义 TCP 的实现逻辑、与上层应用及下层协议的接口,适配多网络分层协议栈架构。

简单来说:TCP 是在“不靠谱”的网络底层之上,给应用层搭的一套“靠谱数据传输管道”。


二、核心机制通俗讲解:把 TCP 当成“可靠快递系统”

1. 整体运行流程与关键角色

你可以把 TCP 的通信过程想象成两家公司之间的可靠快递合作

  • 关键角色
    • 发送端/接收端 TCP:相当于两家的快递调度中心,负责打包、校验、重发、排序快递
    • 应用进程:相当于两家的具体业务部门,要寄/收快递
    • IP 协议:相当于公共快递网络,负责把包裹运到对方公司,不保证不丢、不乱
    • TCB(传输控制块):相当于每个合作的档案袋,记录当前合作的序列号、窗口大小、状态等信息
  • 整体流程
    业务部门把要发的文件给调度中心 → 调度中心打包成快递(TCP 报文段)→ 交给公共快递网络(IP)运输 → 对方调度中心收到后校验、排序 → 交给对方业务部门。如果快递丢了、坏了,调度中心会自动重发。

2. 报文结构:TCP 快递的“面单”长什么样?

TCP 报文段直接封装在 IP 数据报中传输,固定头部 20 字节,后方为可选选项和数据,结构类似快递的「面单+货物」:

表格

字段通俗解释核心作用
源端口/目的端口发件/收件部门的编号确定是哪两个应用在通信,比如网页服务默认用 80 端口,FTP 默认用 21 端口
序列号每个字节的快递单号给每个传输的字节编号,哪怕快递乱序,收件方也能按单号排好顺序
确认号“我已收到单号 X 之前的所有快递”告诉对方我下次要从哪个字节开始收,确认对方的数据我已收到
控制位(URG/ACK/PSH/RST/SYN/FIN)特殊指令标记SYN=我要建立合作,ACK=我收到你的消息了,FIN=我没快递要发了,RST=出错了终止合作,PSH=这个快递要马上送,URG=这个快递是加急
窗口“我现在最多能收 100 件快递”流量控制核心,告诉对方我当前能接收的字节数,对方不能超过这个量发送
校验和快递包装的防震检查检查报文有没有损坏,坏了就直接丢弃,要求重发
紧急指针加急快递的标记配合 URG 标志,指向加急数据之后的位置,告诉对方哪部分是急件

3. 连接交互:三次握手建连,四次挥手断连

TCP 的所有通信都要先建立连接,就像合作前要签合同:

三次握手(建立连接)
  1. 第一步:客户端(A)发SYN包:“我要和你建立连接,我的初始单号是 X”(相当于 A 给 B 发合作意向书)
  2. 第二步:服务端(B)回SYN+ACK包:“我收到你的意向了,我也同意合作,我的初始单号是 Y,我确认收到你的 X 单号”(B 回意向书,附上自己的单号)
  3. 第三步:A 回ACK包:“我收到你的意向了,确认你的 Y 单号”(A 回确认,合同生效,连接建立)
四次挥手(关闭连接)
  1. 第一步:A 发FIN包:“我没快递要发了,准备终止合作”(A 说我要结束了)
  2. 第二步:B 回ACK包:“我知道你发完了”(B 说我知道了)
  3. 第三步:B 发FIN包:“我也没快递要发了”(B 也说要结束)
  4. 第四步:A 回ACK包:“我知道你也发完了,拜拜”(A 确认,然后等 2 倍 MSL 时间再彻底终止,防止 B 没收到确认)

4. 协议依赖:TCP 在协议栈里的位置

根据 RFC 793 的协议关系图,TCP 的分层位置如下:

应用层(Telnet/FTP/Voice 等) ↓ 主机层(TCP/RTP 等其他主机协议) ↓ 网关层(IP 协议 + ICMP) ↓ 网络层(以太网/ARPANET 等本地网络协议)
  • 下层依赖 IP:TCP 完全不关心下层网络是什么,只要 IP 能提供不可靠的数据报服务就行,IP 负责跨网络路由、分片重组。
  • 上层服务应用:应用不需要自己处理重传、排序、流控,直接调用 TCP 的OPEN/SEND/RECEIVE/CLOSE接口就能实现可靠通信。

三、开发者必知:5 个排错/开发核心要点

1. 序列号的“环形”规则与安静时间

  • 序列号是 32 位无符号整数,所有计算要对2^32取模(范围是 0~2^32-1,到顶后回到 0),比较的时候不能用普通的>/<,要用模运算比较。
  • 初始序列号(ISN)每 4 微秒加 1,4.55 小时循环一次,避免旧连接报文干扰。如果 TCP 崩溃后丢失了序列号记忆,必须等 2 分钟(MSL,最大报文生存时间)才能发任何报文,这个“安静时间”是强制要求。

2. 窗口不能随便缩,零窗口要探测

  • 已经公布的窗口不能主动缩小,只能等应用层消费数据后自然扩大,不然会丢包触发不必要的重传。
  • 如果接收方窗口为 0,发送方必须每 2 分钟发一次零窗口探测报文,不然接收方窗口重新打开后无法通知发送方。

3. TIME-WAIT 必须等 2MSL

主动关闭连接的一方最后会进入TIME-WAIT状态,必须等4 分钟(2 倍 MSL)才能彻底关闭,这是为了处理最后 ACK 丢失的场景,不然会导致连接状态异常。

4. SYN/FIN 占序列号,ACK 不占

  • SYNFIN控制位会各占用 1 个序列号,ACK纯确认报文不占用序列号空间,这点经常被忽略导致序列号计算错误。

5. 校验和必须覆盖伪头部

TCP 的校验和计算不仅要算 TCP 头部和数据,还要算伪头部(源 IP、目的 IP、协议号、TCP 长度),不然可能出现 IP 路由错误但 TCP 仍然接收报文的问题。


四、总结

一句话记住 TCP:在不可靠的 IP 网络之上,用三次握手建连、序列号排序、ACK 确认、超时重传、滑动窗口流控,实现可靠有序全双工通信的传输层协议。