TCP协议概述
TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议。它通过一系列机制确保数据准确、有序地从发送方传递到接收方,适用于对可靠性要求高的场景(如网页浏览、文件传输)。
可靠传输的核心机制
三次握手建立连接
TCP通过三次握手(Three-Way Handshake)初始化连接,确保双方具备收发能力:
- SYN:客户端发送SYN=1和随机序列号seq=x,进入SYN_SENT状态。
- SYN+ACK:服务器回复SYN=1、ACK=1,确认号ack=x+1,并发送自己的序列号seq=y,进入SYN_RCVD状态。
- ACK:客户端发送ACK=1,确认号ack=y+1,双方进入ESTABLISHED状态。
意义:防止历史重复连接初始化导致资源浪费,同步双方的初始序列号。
四次挥手释放连接
终止连接需四次挥手(Four-Way Handshake),因TCP全双工特性需分别关闭双向通道:
- FIN:主动方发送FIN=1和序列号seq=u,进入FIN_WAIT_1状态。
- ACK:被动方回复ACK=1和确认号ack=u+1,进入CLOSE_WAIT状态;主动方收到后进入FIN_WAIT_2。
- FIN:被动方发送FIN=1和序列号seq=v,确认号ack=u+1,进入LAST_ACK状态。
- ACK:主动方回复ACK=1和确认号ack=v+1,进入TIME_WAIT状态(等待2MSL后关闭)。
TIME_WAIT作用:确保最后一个ACK到达被动方,并让网络中残留的数据包失效。
流量控制(滑动窗口)
通过接收方的**窗口字段(rwnd)**动态调整发送速率,避免接收方缓冲区溢出:
- 滑动窗口机制:发送方维护一个发送窗口,仅发送窗口内的数据;接收方通过ACK告知剩余缓冲区大小(rwnd)。
- 零窗口处理:若rwnd=0,发送方暂停发送并周期性探测窗口状态。
拥塞控制
防止网络过载,包含四种算法:
- 慢启动(Slow Start):窗口从1开始,每收到一个ACK加倍增长,直至阈值(ssthresh)。
- 拥塞避免:窗口线性增长,避免过快引发丢包。
- 快速重传:收到3个重复ACK时立即重传丢失报文。
- 快速恢复:重传后直接进入拥塞避免阶段,而非慢启动。
公式:
窗口增长规则(慢启动阶段)
$$ cwnd = cwnd + 1 \ \text{per ACK} \ \Rightarrow \ \text{指数增长} $$
延时应答(Delayed ACK)
接收方延迟发送ACK(通常200ms),减少报文数量并提高吞吐量。在此期间若有数据需回复,则捎带ACK。
面向字节流与粘包问题
- 字节流特性:TCP将数据视为无结构的字节流,不保留应用层报文边界。
- 粘包原因:发送方多次写入的数据可能被合并发送;接收方缓冲区可能一次性读取多个报文。
- 解决方案:
- 固定长度报文(如每100字节为一个消息)。
- 特殊分隔符(如
\n
)。 - 自定义头部(如长度字段+数据内容)。
实际应用示例
Wireshark抓包分析:观察三次握手报文中的SYN/ACK标志、序列号变化,以及滑动窗口字段的动态调整。
代码示例(粘包处理):
# 使用长度头部解决粘包
import struct
def send_data(sock, data):
length = len(data)
sock.send(struct.pack('I', length) + data) # 4字节长度头
def recv_data(sock):
header = sock.recv(4)
length = struct.unpack('I', header)[0]
return sock.recv(length)
通过上述机制,TCP实现了高可靠性传输,平衡了效率与公平性,成为互联网基石协议之一。