- 序号:
- 数据段中第一个字节在数据流中的位置编号
- 确认号:
- 期望从另外一边收到的下一个字节的序号
- 累积确认
三次握手建立连接
- 客户端发送 SYN 请求建立连接,指定初始序号。
- 服务器回复 SYN 和 ACK 同意连接,指定服务端初始序号。
- 客户端回复 ACK 表示收到,可能包含数据。
四次挥手关闭连接
- 客户端发送 FIN 请求关闭连接(不能发送只能接收数据了)
- 服务器回复 ACK 并进行扫尾工作(扫尾时还可以发送数据)
- 服务器回复 FIN 表示可以关闭了
- 客户端回复 ACK 表示收到,随后进入超时等待
MSS(最大数据段长度): TCP 报文段中数据字段的最大长度,而 MSS 通常根据 MTU(最大链路层帧)来设置。
流量控制
- 接收方在 TCP 头部消息中 rwnd 字段 ” 通知 ” 发送方剩余缓存区大小
- rwnd 为零的时候还会继续发送探测报文
- 如果后续接收方缓冲区有空间了(例如应用读取了数据),接收方需要通知发送方更新窗口。但此时如果双方都没有数据交互,接收方无法主动发送 ACK(因为 TCP 的 ACK 通常是“附带”在数据报文中的)。发送方定期发送1 字节的探测报文(不携带实际应用数据),迫使接收方返回 ACK,并在 ACK 中携带最新的
rwnd
值。
- 如果后续接收方缓冲区有空间了(例如应用读取了数据),接收方需要通知发送方更新窗口。但此时如果双方都没有数据交互,接收方无法主动发送 ACK(因为 TCP 的 ACK 通常是“附带”在数据报文中的)。发送方定期发送1 字节的探测报文(不携带实际应用数据),迫使接收方返回 ACK,并在 ACK 中携带最新的
- 发送方限制🚦已发送但是未被确认的数据量不超过 rwnd:
设置超时
如何设置 TCP 超时值?
应该要比 RTT 长,但是 RTT 是要变化的。如果太短会产生很多不必要的重传,如果太长则在丢包产生的时候响应变慢
这里利用 RTT 估计值和安全余量设置超时
先搞一个 RTT 估计值:(每次产生的 RTT 记录为 )
每次 RTT 都能够刷新一个平均值(有点像那个股市的平均了)
再搞一个安全余量:
最后的超时值:
- 初始值设置:
- 首次计算时,
EstimatedRTT
初始化为第一个SampleRTT
。 DevRTT
初始化为SampleRTT / 2
。
- 首次计算时,
- 超时值的下限:
- RFC 6298 要求超时值至少为 1 秒(防止过早超时)。
- 重传后的退避(Backoff):
- 若发生超时重传,下次超时值会加倍(类似指数退避)。
快速重传
收到 3 个对同样报文段的确认,则认为该报文段之后的数据丢失,启动快速重传:在定时器超时之前重发
拥塞控制
Tahoe
- 慢启动:每个传输回合 cwnd 自乘 2,即每收到一个 ACK,cwnd+1MSS,若 cwnd 达到 ssthresh,进入拥塞避免状态。
- 拥塞避免:cwnd 每个传输回合自增 1
- 超时:超时了,当前的 ssthresh 的值设置为当前 cwnd 的一半,将 cwnd 设置为 1
- 快速恢复: 收到了 3 个冗余 ACK,当前的 ssthresh 的值设置为当前 cwnd 的一半,将 cwnd 设置为(更新后的)ssthresh+ 3MSS(cwnd 减半加 3MSS),立即发送
Reno
丢包和 3 次冗余 ACK 都将 cwnd 设为 1 个 MSS
TCP 公平
公平的目标是每个 TCP 应该对带宽为 R 的瓶颈链路有 R/K 的平均速率
- TCP 为什么是公平的
- 两个竞争的会话:
- 按照斜率 1 加性增加, 同时吞吐量增加
- 乘性降低等比例减少吞吐量
- 图中每一个点的横纵坐标表示两个连接的带宽利用率,它们的和是一定的。从红色线起点出发,沿着红色路径移动,最终会趋近于 y=x 所在的直线,即达到公平。
可以这么理解:
- 加性增加时,两个连接都慢慢加窗口,方向是斜率 1(一起涨)。
- 遇到拥塞时都等比例减少窗口(乘性减少)。
- 在不断重复这个过程时,会自动调整到公平的状态(两个连接吞吐量相等)。