TCP:概述
点对点(point-to-point):一个 sender,一个 receiver
可靠数据传输服务 RDT
全双工服务(full duplex service):数据双向流动
连接面向(connection-oriented):数据交换前握手确立连接
网络层:连接应用层与链路层
- 维护一个缓冲区(buffer),发送端为发送缓冲区,接收端为接收缓冲区;应用程序通过套接字向缓冲区内写入/读取数据。
- 发送数据时,TCP 每次从缓冲区中取出
MSS 大小 的块(chunk),加入 TCP 头组成 TCP 报文段(segment)。报文段随后被交给网络层,封装成 IP 数据报(datagram)发送出去。
最大报文段长度(Maximum Segment Size, MSS)指的是 TCP 报文段允许的应用层数据最大长度(不包括 TCP 头)。它由本地链路层的最大传输单元(Maximum Transmission Unit, MTU)减去 TCP/IP 头长度来确定,通常为 1460 字节。
TCP 报文段结构

TCP 头的标准长度(可变长度的 option 栏为空):$20$ 字节($32\times 5/8$)
建立连接:TCP 三次握手
壹:客户端向服务器发送 SYN 报文段(SYN=1),携带客户端初始序号 seq=client_isn,请求建立连接
贰:服务器收到 SYN 后,分配资源如缓冲区,TCP 变量等,回复 SYNACK 报文段(SYN=1, ACK=1),携带服务器初始序号 seq=server_isn,同时确认客户端的序号 ack=client_isn+1(关于 ACK 机制的详细介绍见后文)
叁:客户端收到 SYNACK 后,发送 ACK 报文段作为最终确认,seq=client_isn+1 并确认服务器端的序号 ack=server_isn+1
TCP 如何实现 RDT
关于序号(sequence number):TCP 视数据为有序的字节流(ordered stream of byte),并将数据切成 $\leq \text{MSS}$ 的块,每块加上头封装为 TCP 报文段。报文段的序号由数据块中的首个字节在字节流中的位置决定。
关于 ACK 行为:类似 GBN 的累计确认(cumulative ACK),ACK $x$ 表示:我确认收到了 $x$ 之前的所有字节,接下来我
接收端如何处理乱序包:丢弃或者缓存,依具体实现而定。
重传机制之壹:计时器(timer)追踪最早的未被 ACK 的报文段(类似 GBN),超时后触发重传(与 GBN 不同,只重传该 base 段而非 [base, nextseqnum-1] 中的所有段)。计时器在重传后或 base 更新时重置。
重传机制之贰:快速重传(fast retransmit)
- intuition:基于超时的重传延迟很大。发送方常连续(back-to-back)发送多个段,因此若有段丢失,发送方几乎总能收到 duplicate ACKs
- 若发送方收到 3 个 duplicate ACK $x$(注意,
3 个 duplicate ACKs 不包括第一次的 new ACK,所以共有 4 个 ACKs ),说明段 $x$ 丢失,在超时前就进行重传
流量控制
当接收方应用程序从接收缓冲区中读取数据的速度跟不上发送方传输数据的速度时,容易出现缓冲区溢出导致丢包的现象。TCP 提供流量控制(flow control)服务,使发送方发送数据的速率与接收方应用程序读取数据的速率相匹配。
假设 $A$ 向 $B$ 发送数据,$B$ 接收缓冲区的大小为 RcvBuffer,$B$ 维护两个变量 LastByteRead 与 LastByteRcvd,计算接收窗口(receive window)大小为 rwnd = RcvBuffer-(LastByteRcvd-LastByteRead),将其填入 ACK 报文段 TCP 头中对应的字段。
$A$ 维护两个变量 LastByteSent 与 LastByteAcked,每次发送数据前检查是否有 LastByteSent-LastByteAcked ≤ rwnd,若不满足,表示当前已发送但尚未被确认的数据已经能够占满 $B$ 的接收缓冲区,所以停止发送。
当 rwnd = 0 时,$A$ 需要发送单字节的报文段以探测 $B$ 的接收窗口是否开始释放。
关闭连接
壹:客户端向服务器发送 FIN 报文段(FIN=1),表示客户端已经没有数据要发送了,请求关闭客户端 $\to$ 服务器连接。此时客户端进入 FIN_WAIT_1 状态,不再发送数据,但仍能接收服务器发来的数据
贰:服务器收到 FIN 后,回复 ACK 报文段(ACK=1)进行确认。此时服务器进入 CLOSE_WAIT 状态,说明其已经知道客户端不再发送数据,但服务器自己可能仍有数据未发送完
- 客户端收到该
ACK后进入FIN_WAIT_2状态,等待服务器发来FIN
叁:服务器发送完剩余数据,向客户端发送 FIN 报文段(FIN=1),表示服务器没有数据要发送了,请求关闭服务器 $\to$ 客户端连接。此时服务器进入 LAST_ACK 状态,等待客户端最终确认
肆:客户端收到 FIN 后,回复 ACK 报文段(ACK=1)进行确认,表示收到服务器的关闭请求。此时客户端进入 TIME_WAIT 状态,等待一段时间后才真正关闭连接;服务器收到该 ACK 后立即进入 CLOSED 状态,连接正式关闭