什么是 Tcp
三次握手
-
tcp client发送连接请求报文,报文首部同步标记位 SYN=1 同时随机序列号 seq=x,此时 tcp client 进入
SYNC-SENT
状态的 -
tcp server 若同意连接则确认报文为
ACK=1,SYN=1,ASK=x+1,seq=y
返回给客户端,并进入SYNC_RCVD
状态 -
tcp client 收到回复并确认 ACK 是否为1,seq 是否为 x+1,并返回报文
ACK=1,ASK=y+1
,此时双方进入ESTABLISHED
状态
四次挥手
-
主动方发送报文
FIN=1,seq=last+1
并进入FIN_WAIT_1
,此时报文不能携带任何数据 -
被动方收到连接释放报文,并发送确认报文
ACK=1,ack=u+1,seq=v
,并进入CLOSE_WAIT
状态,但此时如果缓冲区存在未发送数据,那么需要继续发送(这也是 CLOSE_WAIT 持续的时长),主动方收到此条报文后进入FIN_WAIT_2
,因为还需要处理未发送数据 -
上一步执行完毕,被动方发送
FIN=1,ack=w+1,seq=u+1
并进入LAST-ACK
状态,而主动方收到此条报文后进入TIME_WAIT
(2msl maximum segment life),之后才会进入CLOSED
-
在主动方进入
CLOSED
之前,需要发送报文确认退出
2MSL
1MSL保证主动方最后的 ACK 能到达对端,1MSL 确保 ACK 重传
如何确保可靠性
-
三次握手,四次挥手确保连接和断开的可靠
-
记录了哪些数据被接受,哪些未接收,序列号保证了消息的顺序性
-
ACK应答,超时重传,失序重传,丢弃重复数据,流量控制,拥塞控制
重传机制
RTT,RTO
Round-Trip Time 消息往返时间 Retransmission Timeout 超时重传
快速重传
不以时间为驱动,而是以接收方返回信息触发
滑动窗口
本质上是内核开辟了一个缓冲区,依据tcp头部的win(16bit) 来确认,其大小表示无需等待确认应答,可以发送或接收数据的最大值,在发送确认报文的时候同时告知对方
- 发送窗口
分为四段,已发送已确认,已发送未确认,未发送但可发送,未发送但不可发送
- 接收窗口
分为三段,已接收并确认,未接收但可以接收,未接收且不可接收
拥塞机制
拥塞控制是作用于网络的,防止过多的数据包注入到网络中,避免出现网络负载过大的情况。它的目标主要是最大化利用网络上瓶颈链路的带宽。它跟流量控制又有什么区别呢?流量控制是作用于接收者的,根据接收端的实际接收能力控制发送速度,防止分组丢失
发送方维护一个 cwnd 窗口,估算当前网络可以承载的数据量,它是动态的,只要没有出现阻塞就增大一些,若阻塞则减少一些
拥塞算法
- 慢启动
连接建立完成后,先探测网络的拥塞程度,如果未出现丢包,没收到一个ACK,cwnd+1(MSS),每一个RTT过后cwnd增加一倍,若出现丢包则减半
- 拥塞避免
当cwnd超过慢启动阈值ssthresh
时,进入拥塞避免,一般是64kb,即cwnd不再增加
- 拥塞发生
当网络拥塞发生丢包时,存在两种情况: RTO超时重传,慢启动阈值减半,cwnd = 1,并重新进入慢启动。发送发收到3个重复的ACK时进入快速重传,cwnd=cwnd/2,ssthresh = cwnd,并进入快速恢复
- 快速恢复
cwnd = ssthresh +3 ,重传丢失的的数据包,如果再收到重复的ACK,则 cwnd+1,当收到新的ACK后(即恢复正常)cwnd=ssthresh,并重新进入拥塞避免
半连接
即tcp server 回复 ACK,SYN
后,这个连接被推入了SYN队列,即半连接队列,若 tcp client 确认并回复ACK后则会被推入Aceept队列,即全连接队列
预防 SYN FLOOD
伪造不存在ip,发送大量的SYN报文,导致服务器无法收到正确的ACK报文,以至于半连接队列满载
-
SYN PROXY 代理真实服务器的半连接队列
-
SYN COOKIE 服务器拦截原始SYN报文,这个太硬核
粘包和拆包
由于发送缓冲区的关系,以及读取缓冲区的关系,一般由业务层决定(固定长度,长度+消息,请求应答)