TCP¶
三次握手原因¶
- 阻止历史重复连接的初始化(主要原因)
- 同步双方的初始序列号
- 接收方可以去除重复的数据;
- 接收方可以根据数据包的序列号按序接收;
- 可以标识发送出去的数据包中, 哪些是已经被对方收到的;
- 避免资源浪费
- 连接请求阻塞后到达,服务端会建立多个冗余的无效链接,造成不必要的资源浪费
TCP 三次握手
计时器¶
- 重传计时器:Retransmission Timer
重传定时器:为了控制丢失的报文段或丢弃的报文段,也就是对报文段确认的等待时间。当TCP发送报文段时,就创建这个特定报文段的重传计时器,可能发生两种情况:若在计时器超时之前收到对报文段的确认,则撤销计时器;若在收到对特定报文段的确认之前计时器超时,则重传该报文,并把计时器复位。
- 时间等待计时器:Time_Wait Timer
在连接终止期使用,当TCP关闭连接时,并不认为这个连接就真正关闭了,在时间等待期间,连接还处于一种中间过度状态。这样就可以时重复的fin报文段在到达终点后被丢弃。(2MSL)
- 保活计时器:Keeplive Timer
没有数据要发送,仅仅就想尝试确认对方是否依然在线。每当服务器收到客户的信息,就将keeplive timer复位,超时通常设置2小时,若服务器超过2小时还没有收到来自客户的信息,就发送探测报文段,若发送了10个探测报文段(每75秒发送一个)还没收到响应,则终止连接。
- 坚持计时器:Persistent Timer 专门为对付零窗口通知而设立的
当发送端收到零窗口的确认时,就启动坚持计时器,当坚持计时器截止期到时,发送端TCP就发送一个特殊的报文段,叫探测报文段,这个报文段只有一个字节的数据。探测报文段有序号,但序号永远不需要确认,甚至在计算对其他部分数据的确认时这个序号也被忽略。探测报文段提醒接收端TCP,确认已丢失,必须重传。
坚持计时器的截止期设置为重传时间的值,但若没有收到从接收端来的响应,则发送另一个探测报文段,并将坚持计时器的值加倍和并复位,发送端继续发送探测报文段,将坚持计时器的值加倍和复位,知道这个值增大到阈值为止(通常为60秒)。之后,发送端每隔60s就发送一个报文段,直到窗口重新打开为止。
TIME_WAIT 等待的时间¶
2MSL: 网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。
原因:
- 防止旧连接的数据包
- 保证「被动关闭连接」的一方能被正确的关闭,即保证最后的 ACK 能让被动关闭方接收
time_wait状态码过多¶
重用,快速回收,设置最大值
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系默认的 TIMEOUT 时间
close_wait¶
被关闭一方在收尾阶段时,socket 不能执行 close( ),不能发送 FIN
- 程序问题:旧的请求使用数据库线程池,但是没有及时释放连接
- 新的客户端等待时间长,主动发起关闭
- 客户端响应这个关闭请求,但是服务端请求处理的线程还在阻塞,无法下一步发送 FIN
- 也可能是没有捕获异常
可以通过jstack来分析线程堆栈。
TCP保证可靠性¶
应用数据被分割成 TCP 认为最适合发送的数据块。
TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
TCP 的接收端会丢弃重复的数据。
流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)
拥塞控制: 当网络拥塞时,减少数据的发送。
- 慢开始 : 小到大逐渐增加拥塞窗口的大小 ( 加倍 )
- 避免拥塞 :拥塞窗口按线性规律缓慢增长 (先指数增长(16),再线性增长,遇到拥塞时归1,并调整指数上限)
- 快重传 : 收到三个重复确认就应当立即重传对方尚未收到的报文段,不等计时器。但是还面临重传之前的一个还是重传所有的问题。
- 快恢复:当发送方连续收到三个重复确认时,将拥塞窗口设为较小的指数上限值,然后开始线性增长

ARQ协议(停止等待): 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
接收端给发送端的 Ack 确认只会确认最后一个连续的包。使用快重传还时面临重传之前的一个还是重传所有的问题。
SACK:TCP头里加 SACK

意外情况¶
SYN丢失(响应的「SYN,ACK」丢失)¶
某端的一组「请求-应答」中,在一定时间范围内,只要没有收到应答的「ACK」包,无论是请求包对方没有收到,还是对方的应答包自己没有收到,均认为是丢包了,都会触发超时重传机制。
服务端发送「SYN,ACK」包重传5次后,客户端仍未响应,则关闭连接。
客户端最后一次回复「SYN,ACK」的「ACK」包丢失¶
丢失后发送数据包时,会携带上一个「ACK」的确认序号,所以哪怕客户端响应的「ACK」包丢了,服务端在收到这个数据包时,能够通过包内 ACK 的确认序号,正常进入 ESTABLISHED 状态。
请求断开连接的 FIN 包丢失¶
超时重传
服务端第一次回复的「ACK」丢失¶
服务端继续回复「FIN,ACK」,携带了之前「ACK」的响应序号,客户端可以凭借「FIN,ACK」包中的响应序号,直接从 FIN-WAIT-1 状态,进入 TIME-WAIT 状态,开始长达 2MSL 的等待。
服务端发送的「FIN,ACK」丢失¶
超时重传
客户端最后回复的 ACK 丢失¶
重试一段时间,直到服务端重试超时后主动断开。
同时主动连接¶
同时打开时,建立一条连接。当每一端收到SYN时,状态变为SYN_RCVD,同时它们都再发SYN并对收到的SYN进行确认。当双方都收到SYN及相应的ACK时,状态都变迁为ESTABLISHED。

同时关闭¶
同时关闭时,两端均从 ESTABLISHED 变为 FIN _ WAIT_1。双方各发送一个 FIN。收到FIN后,状态由FI N_WAIT_1变迁到 CLOSING,并发送最后的ACK。当收到最后的 ACK时,状态变化为TIME_WAIT。

客户端主动关闭连接 —— TCP 四次挥手

