Skip to content

TCP 协议

TCP(Transmission Control Protocol,传输控制协议)是面向连接的、可靠的、基于字节流的传输层协议。TCP 解决了数据传输的可靠性、顺序性、流量控制、拥塞控制等问题。

TCP 头部格式

源端口和目的端口

16 位,标识发送方和接收方的进程。端口号范围:0-65535,0-1023 为知名端口(如 HTTP 80、HTTPS 443)。

序列号

32 位,标识 TCP 段中第一个字节的序号。序列号是循环使用的,达到 2^32-1 后从 0 开始。

确认号

32 位,期望收到的下一个字节的序号。确认号是累积确认,表示之前的字节都已正确接收。

数据偏移

4 位,TCP 头部的长度,以 4 字节为单位。最小值 5(20 字节),最大值 15(60 字节)。

标志位

URG(紧急指针有效)、ACK(确认号有效)、PSH(推送)、RST(重置连接)、SYN(同步序列号)、FIN(结束连接)。

窗口大小

16 位,接收窗口的大小,用于流量控制。窗口大小最大 65535 字节,通过窗口扩大选项可以扩大到 1GB。

校验和

16 位,检验 TCP 头部和数据的完整性。发送方计算校验和,接收方验证校验和。

紧急指针

16 位,指向紧急数据的最后一个字节。紧急数据需要优先处理。

选项

选项字段可变长,常见选项:MSS(最大段大小)、窗口扩大、时间戳、SACK(选择性确认)。

TCP 连接建立

三次握手

第一次握手:客户端发送 SYN,seq = x。客户端进入 SYN_SENT 状态。

第二次握手:服务端回复 SYN+ACK,seq = y,ack = x + 1。服务端进入 SYN_RCVD 状态。

第三次握手:客户端回复 ACK,seq = x + 1,ack = y + 1。双方进入 ESTABLISHED 状态。

为什么需要三次握手

防止失效的连接请求报文段突然又传送到服务端,产生错误。

客户端的发送连接请求报文段丢失,客户端重传连接请求报文段,连接建立后数据传输完毕,连接释放。第一个丢失的连接请求报文段延迟到达,服务端误认为新的连接请求,发送确认报文段,进入 ESTABLISHED 状态,等待客户端数据,浪费资源。

三次握手可以确认双方的接收和发送能力都正常,同步双方的初始序列号。

SYN 攻击

SYN 攻击是攻击者发送大量 SYN 报文段,不完成三次握手,占用服务端的半连接队列,导致服务端无法处理正常连接。

防御措施:SYN Cookies(不保存半连接状态,根据 SYN 计算 Cookie)、缩短超时时间、增加半连接队列大小、开启 tcp_syncookies。

TCP 连接终止

四次挥手

第一次挥手:主动方发送 FIN,seq = u。主动方进入 FIN_WAIT_1 状态。

第二次挥手:被动方回复 ACK,ack = u + 1。被动方进入 CLOSE_WAIT 状态。主动方收到 ACK 后进入 FIN_WAIT_2 状态。

第三次挥手:被动方发送 FIN,seq = w,ack = u + 1。被动方进入 LAST_ACK 状态。

第四次挥手:主动方回复 ACK,seq = u + 1,ack = w + 1。主动方进入 TIME_WAIT 状态,等待 2MSL 后进入 CLOSED 状态。被动方收到 ACK 后进入 CLOSED 状态。

为什么需要四次挥手

TCP 是全双工协议,双方都可以发送数据。主动方关闭发送通道,但可能还在接收数据。被动方可能还有数据要发送,需要确认数据发送完毕后再关闭发送通道。

TIME_WAIT 状态

TIME_WAIT 状态持续 2MSL,约 60 秒。作用:确保最后的 ACK 能够到达被动方,如果 ACK 丢失,被动方会重传 FIN,主动方可以重发 ACK。确保旧连接的报文段在网络中消失,不影响新连接。

TIME_WAIT 状态的问题:占用端口资源,高并发短连接场景下端口可能耗尽。解决方案:开启 tcp_tw_reuse、tcp_tw_recycle(Linux 4.12 已移除)、增加端口范围。

TCP 可靠传输

序列号

序列号标识 TCP 段中第一个字节的序号,用于数据排序、去重、流量控制。

序列号是随机生成的,防止序列号猜测攻击。

确认应答

接收方收到数据后发送 ACK,确认号是期望收到的下一个字节的序号。ACK 是累积确认,表示之前的字节都已正确接收。

超时重传

发送方发送数据后启动定时器,如果超时未收到 ACK,则重传数据。超时时间根据 RTT(Round Trip Time,往返时间)动态调整,RTT 变化大时超时时间也变化大。

快速重传

接收方收到失序报文段后立即发送重复 ACK,发送方收到 3 个重复 ACK 后立即重传报文段,不必等待超时。

选择性确认

SACK(Selective ACK)允许接收方告诉发送方哪些报文段已正确接收,哪些报文段丢失,发送方只需重传丢失的报文段,提高效率。

TCP 流量控制

滑动窗口

接收方通过窗口大小告诉发送方自己可以接收多少数据,发送方根据窗口大小调整发送速率,避免淹没接收方。

窗口大小是接收缓冲区的剩余空间,接收方处理数据后窗口增大,接收方缓冲区满时窗口为 0。

零窗口问题

接收方窗口为 0 时,发送方停止发送数据,定期发送零窗口探测报文段,询问窗口是否打开。

接收方窗口打开后发送 ACK,通知发送方可以继续发送数据。

TCP 拥塞控制

慢启动

连接建立后,拥塞窗口从 1 个 MSS 开始,每收到一个 ACK,拥塞窗口增加 1 个 MSS,指数增长。慢启动阈值(ssthresh)是慢启动和拥塞避免的分界线,拥塞窗口超过 ssthresh 后进入拥塞避免。

拥塞避免

拥塞窗口每 RTT 增加 1 个 MSS,线性增长,避免拥塞。

快速重传

收到 3 个重复 ACK 后,立即重传报文段,不必等待超时。

快速恢复

快速重传后,不进入慢启动,而是将拥塞窗口设置为 ssthresh 的一半,进入拥塞避免。

TCP 是互联网的核心协议,理解 TCP 的连接建立、连接终止、可靠传输、流量控制、拥塞控制,有助于理解网络编程的底层原理。