一、TCP 协议概述

TCP(Transmission Control Protocol,传输控制协议)是 TCP/IP 协议栈中传输层的核心协议。 它提供面向连接的、可靠的、基于字节流的传输服务。 与 UDP 的"尽最大努力交付"不同,TCP 通过序列号、确认应答、重传机制、流量控制和拥塞控制来保证数据可靠到达。

💡 TCP vs UDP 一句话总结

TCP 像打电话 — 先拨号建立连接,确认对方在听,然后逐句交流,说完挂断。UDP 像寄明信片 — 写完直接扔进邮筒,不关心对方是否收到。

二、TCP 报文头部结构

TCP 报文头部固定为 20 字节(不含选项),下图逐字段展示其结构:

TCP 报文头部结构(每格 = 32 bit / 4 字节) 0 8 16 24 31 源端口 Source Port (16 bit) 目的端口 Destination Port (16 bit) 序列号 Sequence Number (32 bit) 确认号 Acknowledgment Number (32 bit) 数据偏移 (4 bit) 保留 (6 bit) 标志位 Flags (6 bit) URG ACK PSH RST SYN FIN 窗口大小 Window (16 bit) 校验和 Checksum (16 bit) 紧急指针 Urgent Pointer (16 bit) 选项 Options (可变长度,0-40 字节,含填充) 数据 Data (应用层数据) 0 4 8 12 16 20 20+
图 1 — TCP 报文头部结构,固定头部 20 字节,最大头部(含选项)60 字节

关键字段说明

字段大小说明
源端口16 bit发送方端口号,标识发送数据的应用
目的端口16 bit接收方端口号,标识接收数据的应用
序列号 (seq)32 bit本报文数据部分第一个字节的编号,保证数据有序到达
确认号 (ack)32 bit期望收到的下一个字节的序号,即"ack 之前的所有数据已收到"
数据偏移4 bitTCP 头部长度(以 4 字节为单位),实际头部长度 = 此值 × 4
窗口大小 (Window)16 bit接收方告知发送方自己还能接收多少数据,用于流量控制
校验和 (Checksum)16 bit覆盖 TCP 头部、数据和伪首部,用于差错检测
紧急指针16 bit当 URG=1 时有效,指出紧急数据末尾在报文中的位置

六个标志位(Flags)

标志全称含义
URGUrgent紧急指针有效,报文含高优先级数据
ACKAcknowledgment确认号有效,除初始 SYN 外几乎所有报文都置 1
PSHPush要求接收方立即将数据交给应用层,不等缓冲区满
RSTReset重置连接,用于异常情况下的连接中断
SYNSynchronize同步序列号,用于建立连接
FINFinish发送方数据已完毕,请求关闭连接

三、三次握手 — 建立连接

TCP 建立连接需要三次交互(Three-Way Handshake),确保双方都准备好通信并同步序列号:

TCP 三次握手过程 Client Server CLOSED SYN_SENT ESTABLISHED LISTEN SYN_RCVD ESTABLISHED ① SYN, seq=x ② SYN+ACK, seq=y, ack=x+1 ③ ACK, seq=x+1, ack=y+1 ✓ 连接建立,双向数据传输开始 x = 客户端初始序列号(ISN) | y = 服务端初始序列号(ISN)
图 2 — TCP 三次握手:SYN → SYN+ACK → ACK,双方各自确认对方的序列号

为什么是三次而不是两次?

如果只有两次握手(Client 发 SYN,Server 回 SYN+ACK 后直接建立连接),存在一个经典问题: 假设 Client 发出的第一个 SYN 因网络延迟迟迟未到达,Client 超时后重发了一个新的 SYN 并成功建立连接、完成数据传输、关闭连接。 之后那个迟到的旧 SYN 到达 Server,Server 回复 SYN+ACK 并建立连接 — 但这个连接 Client 根本不需要,Server 的资源被白白浪费。

三次握手解决了这个问题:Client 收到 Server 的 SYN+ACK 后,还要再发一个 ACK 确认。如果 Client 没有发起连接请求,它不会发 ACK,Server 收不到 ACK 就不会真正建立连接,超时后自动释放。

四、四次挥手 — 关闭连接

TCP 是全双工通信,关闭连接需要双方各自独立关闭自己的发送通道,因此需要四次交互:

TCP 四次挥手过程 Client Server ESTABLISHED FIN_WAIT_1 FIN_WAIT_2 TIME_WAIT CLOSED ESTABLISHED CLOSE_WAIT LAST_ACK CLOSED ① FIN, seq=u Client 主动关闭,不再发数据 ② ACK, ack=u+1 Server 确认,但可能还有数据要发 ③ FIN, seq=v Server 数据发完,也请求关闭 ④ ACK, ack=v+1 Client 确认,等待 2MSL 后关闭 连接完全关闭
图 3 — TCP 四次挥手:FIN → ACK → FIN → ACK,双方各自独立关闭发送通道
💡 TIME_WAIT 状态为什么要等 2MSL?

MSL(Maximum Segment Lifetime)是报文最大生存时间。Client 发出最后一个 ACK 后等待 2MSL 有两个目的: 1. 确保最后一个 ACK 能到达 Server。如果 Server 没收到,会重发 FIN,Client 在 TIME_WAIT 期间还能收到并重新发送 ACK。 2. 等待本连接的所有残留报文在网络中消亡,防止干扰新连接(如果新连接复用了相同的端口和序列号)。

五、TCP 可靠性机制总结

机制解决的问题实现方式
序列号 + 确认号数据乱序、重复每个字节编号,按序组装
超时重传数据丢失发送后启动定时器,超时未收到 ACK 则重传
滑动窗口流量控制接收方通过 Window 字段通告可用缓冲区大小
拥塞控制网络拥塞慢启动、拥塞避免、快重传、快恢复
校验和数据损坏对头部和数据计算校验和,接收方验证
✅ 总结

TCP 的复杂性全部服务于一个目标:在不可靠的 IP 网络之上提供可靠的数据传输。理解 TCP 头部结构和状态机转换,是分析网络问题(如连接超时、丢包、重传)的基础。Wireshark 抓包时,每一个字段都能在这张结构图中找到对应位置。