linux31 网络编程TCP协议
TCP(传输控制协议)是 TCP/IP 协议族的核心协议,运行在 IP 层之上,提供面向连接、可靠、有序、字节流的传输服务,是 HTTP、FTP、SSH 等应用层协议的基础。
核型特性
面向连接:通信前需通过 “三次握手” 建立连接,通信后通过 “四次挥手” 释放连接,确保通信双方状态同步。
可靠传输:通过序号、确认号、重传机制、流量控制、拥塞控制,保证数据无丢失、无重复、无差错。
有序传输:按发送端的字节流顺序交付数据,接收端会重组乱序报文段。
字节流服务:将应用层数据视为连续字节流,不保留应用层消息边界(需应用层自行处理分包 / 粘包)。
双工通信:通信双方可同时发送和接收数据,双向独立传输。
面向字节的流量控制:通过滑动窗口机制,避免接收端因缓冲区满而丢失数据。
核心建立流程(三次握手 四次挥手)
1. 三次握手(建立连接)
目的:同步通信双方的序号和确认号,确保双方收发能力正常,避免 “失效连接请求” 干扰。
过程拆解:
客户端(C)→ 服务器(S):发送 SYN 报文(
SYN=1,seq=x),请求建立连接,客户端进入SYN_SENT状态。服务器(S)→ 客户端(C):发送 SYN+ACK 报文(
SYN=1,ACK=1,seq=y,ack=x+1),确认客户端请求并发起连接,服务器进入SYN_RCVD状态。客户端(C)→ 服务器(S):发送 ACK 报文(
ACK=1,seq=x+1,ack=y+1),确认服务器连接,双方进入ESTABLISHED状态(连接建立,可传输数据)。
关键细节:
第三次握手不可省略:若仅两次握手,服务器无法确认客户端已收到自己的 SYN+ACK,可能导致服务器资源浪费(维护无效连接)。
序号
seq:标识发送端当前发送的字节流起始序号(随机初始化,避免序号冲突)。确认号
ack:标识期望接收的下一字节序号(= 对端发送的seq+1)。
2. 四次挥手(释放连接)
目的:确保双方已发送的所有数据都被接收,有序释放连接资源(端口、缓冲区等)。
- 过程拆解:
主动关闭方(如 C)→ 被动关闭方(如 S):发送 FIN 报文(
FIN=1,seq=u),表示不再发送数据,主动方进入FIN_WAIT_1状态。被动关闭方(S)→ 主动关闭方(C):发送 ACK 报文(
ACK=1,seq=v,ack=u+1),确认 FIN,被动方进入CLOSE_WAIT状态(仍可接收数据),主动方进入FIN_WAIT_2状态。被动关闭方(S)→ 主动关闭方(C):所有数据发送完毕后,发送 FIN 报文(
FIN=1,ACK=1,seq=w,ack=u+1),表示不再发送数据,被动方进入LAST_ACK状态。主动关闭方(C)→ 被动关闭方(S):发送 ACK 报文(
ACK=1,seq=u+1,ack=w+1),确认 FIN,主动方进入TIME_WAIT状态(等待 2MSL,确保被动方收到 ACK),被动方收到 ACK 后进入CLOSED状态。
- 关键细节:
四次挥手的原因:TCP 是双工通信,双方需分别关闭 “发送通道”,因此需要两次 FIN+ACK 交互。
TIME_WAIT状态:时长为 2MSL(最大报文段生存时间,默认约 1 分钟),目的是重传可能丢失的 ACK,避免后续新连接收到旧连接的残留报文。

可靠传输机制(核心保障)
1. 序号与确认号(基础)
序号
seq:每个字节流都有唯一序号(如发送 100 字节数据,seq=100,则下一个字节序号为 200)。确认号
ack:接收端通过 ACK 报文告知发送端 “已正确接收至序号 N-1,期望接收序号 N”。作用:解决 “数据丢失”“数据重复” 问题(发送端未收到 ACK 则重传,接收端通过序号去重)。
2. 重传机制(恢复丢失数据)
TCP 通过两种方式检测数据丢失,触发重传:
超时重传:发送端发送报文后启动计时器,若超时未收到 ACK,则重传该报文(超时时间会动态调整,避免网络延迟导致误重传)。
快速重传:接收端收到乱序报文时,连续 3 次发送对 “期望序号” 的 ACK(如期望序号 100,却收到 150,则连续发送 ack=100),发送端收到后立即重传丢失的报文(无需等待超时,效率更高)。
3. 滑动窗口机制(流量控制 + 高效传输)
核心目的:
流量控制:让发送端的发送速率适配接收端的接收能力(避免接收端缓冲区满而丢失数据)。
高效传输:允许发送端在收到 ACK 前连续发送多个报文(批量传输,减少等待时间)。
工作原理:
接收端通过 TCP 报文头部的 “窗口大小” 字段,告知发送端自己当前的缓冲区剩余容量(如窗口大小 = 1024,表示可接收 1024 字节数据)。
发送端的 “发送窗口”= 接收端的 “接收窗口”,发送端只能在窗口内发送数据,窗口随 ACK 确认而 “滑动”(如发送 1024 字节并收到 ACK,窗口向右滑动 1024 字节)。
4. 拥塞控制(避免网络过载)
TCP 不仅要适配接收端能力,还要适配网络带宽(避免大量数据涌入网络导致拥塞),核心算法分为 4 个阶段:
慢启动:初始发送窗口很小(如 1 个报文段),每收到一个 ACK,窗口大小翻倍(指数增长),直到达到 “慢启动阈值(ssthresh)”。
拥塞避免:窗口达到 ssthresh 后,每轮 RTT(往返时间)窗口大小 + 1(线性增长),避免快速拥塞。
拥塞发生:
超时重传:认为网络严重拥塞,ssthresh = 当前窗口 / 2,窗口重置为 1,重新进入慢启动。
快速重传:认为网络轻度拥塞,ssthresh = 当前窗口 / 2,直接进入拥塞避免(窗口不重置,效率更高)。
快速恢复:快速重传后,窗口直接设置为 ssthresh,进入拥塞避免(减少恢复时间)。
TCP 报文段格式(核心字段解析)
TCP 报文段由 “头部 + 数据” 组成,头部最小 20 字节(不含选项字段),关键字段如下:
| 字段 | 长度 | 核心作用 |
|---|---|---|
| 源端口 | 16 位 | 标识发送端应用程序端口(如 HTTP 默认 80) |
| 目的端口 | 16 位 | 标识接收端应用程序端口 |
| 序号(seq) | 32 位 | 标识当前报文段数据的起始字节序号 |
| 确认号(ack) | 32 位 | 期望接收的下一字节序号(仅当 ACK=1 时有效) |
| 数据偏移 | 4 位 | 表示 TCP 头部长度(以 4 字节为单位,最小值 5→20 字节) |
| 控制位(6 位) | 6 位 | SYN(连接请求)、FIN(关闭请求)、ACK(确认)、RST(重置连接)、PSH(推送数据)、URG(紧急数据) |
| 窗口大小 | 16 位 | 接收端的接收窗口大小(流量控制的核心字段) |
| 校验和 | 16 位 | 校验整个报文段(头部 + 数据),检测传输错误 |
| 紧急指针 | 16 位 | 仅当 URG=1 时有效,指向紧急数据的末尾(优先传输紧急数据) |
| 选项字段 | 可变 | 如 MSS(最大报文段大小,默认 1460 字节)、窗口扩大因子、时间戳(防序号回绕) |
常见问题
1. 粘包与分包问题(字节流特性导致)
粘包:发送端连续发送的小数据,被 TCP 合并为一个报文段发送(如发送 “Hello”“World”,接收端可能收到 “HelloWorld”)。
分包:发送端的大数据,被 TCP 拆分为多个报文段发送(如发送 10000 字节,可能拆分为 10 个 1000 字节报文段)。
解决方式:应用层需定义 “消息边界”,如固定长度、分隔符(如 \n)、消息头 + 消息体(头部标识长度)。
2. 常见异常场景
RST 重置连接:当 TCP 连接状态不一致(如接收端收到无效报文),会发送 RST 报文强制关闭连接(如客户端连接不存在的端口,服务器返回 RST)。
半关闭状态:四次挥手中,主动关闭方发送 FIN 后,仍可接收被动关闭方的数据(
FIN_WAIT_2状态),直到被动关闭方发送 FIN。端口占用:连接处于
TIME_WAIT状态时,端口无法被立即复用(需等待 2MSL),可通过SO_REUSEADDR选项允许端口复用。
3. 适用场景
要求可靠传输的场景:HTTP/HTTPS、FTP(文件传输)、SSH(远程登录)、数据库连接(MySQL)。
不适用场景:实时通信(如视频通话、游戏)、对延迟敏感的场景(优先选 UDP,通过应用层实现可靠传输)。
总结
TCP 的核心价值是 “可靠传输”,通过连接建立、序号确认、重传、流量控制、拥塞控制等机制,解决了 IP 层 “无连接、不可靠” 的问题,成为需要数据完整性的应用场景的首选协议。其设计的核心思路是 “在效率与可靠性之间寻求平衡”—— 既通过滑动窗口实现高效批量传输,又通过多种容错机制保障数据可靠交付。

