一、TCP 通信阶段(面向连接)
1. 连接建立阶段(三次握手)
sequenceDiagram
Client->>Server: SYN(seq=x)
Server->>Client: SYN-ACK(seq=y, ack=x+1)
Client->>Server: ACK(ack=y+1)
- 关键步骤 :
- 客户端发送
SYN
(同步序列号) - 服务端回应
SYN-ACK
(确认客户端序列号+1) - 客户端发送最终
ACK
(确认服务端序列号+1)
- 客户端发送
- 状态变迁 :
- 客户端:CLOSED → SYN_SENT → ESTABLISHED
- 服务端:LISTEN → SYN_RCVD → ESTABLISHED
2. 数据传输阶段
graph LR
A[发送数据] --> B[等待ACK]
B -->|超时未确认| A
B -->|收到ACK| C[滑动窗口移动]
- 核心机制 :
- 可靠传输:序列号确认(SEQ/ACK)
- 流量控制:窗口大小通告(Window Size)
- 拥塞控制:慢启动/快重传/快恢复
- 数据特征 :
- 字节流传输(无明确报文边界)
- 支持全双工通信(双向数据流动)
3. 连接终止阶段(四次挥手)
sequenceDiagram
Client->>Server: FIN(seq=u)
Server->>Client: ACK(ack=u+1)
Server->>Client: FIN(seq=v)
Client->>Server: ACK(ack=v+1)
- 关键步骤 :
- 主动关闭方发送
FIN
- 被动关闭方先回
ACK
,后发FIN
- 最终双方确认关闭
- 主动关闭方发送
- 状态变迁 :
- 主动方:ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
- 被动方:ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
4. 特殊状态(TIME_WAIT)
- 持续时长:2*MSL(Maximum Segment Lifetime,默认60秒)
- 作用:
- 确保最后一个ACK能到达
- 让旧连接的重复报文过期
二、UDP 通信阶段(无连接)
1. 单阶段通信模型
graph TD
A[发送数据报] --> B[接收数据报]
B -->|可能丢失| C[无重传]
B -->|可能乱序| D[应用层处理]
- 核心特征 :
- 无需建立连接(直接发送)
- 无状态维护(服务端不记录客户端信息)
- 每个数据报独立处理
2. 伪连接实现(应用层)
- 某些基于UDP的协议(如QUIC)在应用层实现:
- 连接ID标识会话
- 自定义重传机制
- 加密握手过程
三、协议阶段对比
对比项 | TCP | UDP |
---|---|---|
连接建立 | 需要三次握手 | 无连接建立阶段 |
数据传输 | 可靠有序的字节流 | 不可靠无序的数据报 |
状态维护 | 维护连接状态(序列号、窗口等) | 无状态 |
连接终止 | 需要四次挥手 | 无终止过程 |
资源消耗 | 高(缓冲区、定时器等) | 低 |
典型延迟 | 高(握手/挥手开销) | 低 |
四、编程视角的关键差异
1. TCP 套接字API流程
graph TB
Server[服务端] --> s1[socket()]
s1 --> s2[bind()]
s2 --> s3[listen()]
s3 --> s4[accept()] --> s5[recv()/send()]
s5 --> s6[close()]
Client[客户端] --> c1[socket()]
c1 --> c2[connect()]
c2 --> c3[send()/recv()]
c3 --> c4[close()]
2. UDP 套接字API流程
graph TB
Server[服务端] --> s1[socket()]
s1 --> s2[bind()]
s2 --> s3[recvfrom()] --> s4[sendto()]
Client[客户端] --> c1[socket()]
c1 --> c2[sendto()] --> c3[recvfrom()]
五、典型问题分析
1. TCP 半关闭问题
- 场景 :一方调用
shutdown(SHUT_WR)
后仍可接收数据 - 状态 :进入
FIN_WAIT_1
→FIN_WAIT_2
状态 - 编程注意 :需正确处理
recv()
返回0的情况
2. UDP 粘包/丢包处理
- 解决方案 :
- 添加应用层头部(包含长度字段)
- 实现超时重传机制
- 使用序列号标识数据报
- 示例协议:TFTP(简单文件传输协议)