diff --git a/blogs/computer_network/口水话/TCP.md b/blogs/computer_network/口水话/TCP.md index bb46267..267b9ac 100644 --- a/blogs/computer_network/口水话/TCP.md +++ b/blogs/computer_network/口水话/TCP.md @@ -55,7 +55,7 @@ PSH:告知对方这些数据包收到以后应该马上交给上层应用, 当客户端发送 SYN 到对端,服务端收到后会回复 SYN+ACK,此时会将连接信息放入半连接队列,服务端同时会开启一个定时器,如果超时还未收到 ACK 就会进行 SYN+ACK 重传。一旦收到客户端的 ACK,服务端就开始尝试把它加入另一个全连接队列。 -SYN 洪水攻击就是客户端伪造 IP 发送 SYN 包,服务端回复的 ACK+SYN 去到了一个未知的 IP 地址,势必会造成服务端大量连接处于 SYN_RCVD 状态。而服务器的半连接队列大小也是有限的,如果半连接队列满了,也会出现无法处理正常请求的情况。解决 SYN Flood 攻击的办法是 SYN Cookie 机制,它的原理其实很简单,就是在三次握手的最后阶段才分配连接资源。服务端在收到 SYN 包后不马上分配内存资源,而是根据这个 SYN 包计算出一个 Cookie 值,作为握手第二步的序列号回复 SYN+ACK,等对方回应 ACK 包是校验回复的 ACK 是否合法,如果合法握手成功,分配资源。 +SYN 洪水攻击就是客户端伪造 IP 发送 SYN 包,服务端回复的 ACK+SYN 去到了一个未知的 IP 地址,势必会造成服务端大量连接处于 SYN_RCVD 状态。而服务器的半连接队列大小也是有限的,如果半连接队列满了,也会出现无法处理正常请求的情况。解决 SYN Flood 攻击的办法是 SYN Cookie 机制,它的原理其实很简单,就是在三次握手的最后阶段才分配连接资源。服务端在收到 SYN 包后不马上分配内存资源,而是根据这个 SYN 包计算出一个 Cookie 值,作为握手第二步的序列号回复 SYN+ACK,等对方回应 ACK 包时校验回复的 ACK 是否合法,如果合法握手成功,分配资源。 #### 四次挥手 @@ -63,7 +63,7 @@ SYN 洪水攻击就是客户端伪造 IP 发送 SYN 包,服务端回复的 ACK FIN 同 SYN 报文一样,不管是否携带数据,FIN 段都需要消耗一个序列号,如果 FIN 段不消耗序列号,那么在客户端收到 ACK 报文时是不知道是 Data 的确认包还是 FIN 的确认包。 -在实际情况下,四次挥手进程会变成三次,即第二步和第三步合并了。在客户端发送 FIN 包之后,会进入半关闭状态,表示自己不会再给对方发送数据了,但是服务端还是可以给自己发送数据的,在这种情况下,如果不及时发送 ACK,死等服务端这边发送数据,可能会造成客户端不必要的重发 FIN 包。如果服务端确定没有什么数据需要发送给客户端,当然就可以把 FIN 和 ACK 合并成一个包发送,四次挥手的过程也就变成了三次。 +在实际情况下,四次挥手过程会变成三次,即第二步和第三步合并了。在客户端发送 FIN 包之后,会进入半关闭状态,表示自己不会再给对方发送数据了,但是服务端还是可以给自己发送数据的,在这种情况下,如果不及时发送 ACK,死等服务端这边发送数据,可能会造成客户端不必要的重发 FIN 包。如果服务端确定没有什么数据需要发送给客户端,当然就可以把 FIN 和 ACK 合并成一个包发送,四次挥手的过程也就变成了三次。 同理,三次握手也可以变成四次握手,只是把第二步的 SYN+ACK 拆分开来。与 FIN 不同的是,一般情况下,SYN 包都不携带数据,收到客户端的 SYN 包以后不用等待,可以立马回复 SYN+ACK,四次握手理论上可行,但是现实中并不常见。 @@ -71,7 +71,7 @@ FIN 同 SYN 报文一样,不管是否携带数据,FIN 段都需要消耗一 需要明确的是,只有主动断开的那一方才会进入 TIME_WAIT 状态,且会在那个状态持续 2 个 MSL(报文最大生存时间)。TIME_WAIT 存在的原因是什么呢? -第一个原因是:数据报文可能在发送途中延迟但最终会到达。如果客户端在发送完 FIN 包后不等待直接进入 CLOSE 状态,过一段时间相同的 IP 和端口号又建立一个新的连接,这样收到的数据包就无法知道到底是旧连接的包还是新连接的包了,造成新连接数据的混乱。如果等待时间是 2 个 MSL,已经足够让一个方向上的包最多存活 MSL 秒就被丢弃,保证了在新创建的 TCP 连接以后,老连接姗姗来迟的包已经在网络中被丢弃消逝,不会干扰新连接。 +第一个原因是:数据报文可能在发送途中延迟但最终会到达。如果客户端在发送完 ACK 包后不等待直接进入 CLOSE 状态,过一段时间相同的 IP 和端口号又建立一个新的连接,这样收到的数据包就无法知道到底是旧连接的包还是新连接的包了,造成新连接数据的混乱。如果等待时间是 2 个 MSL,已经足够让一个方向上的包最多存活 MSL 秒就被丢弃,保证了在新创建的 TCP 连接以后,老连接姗姗来迟的包已经在网络中被丢弃消逝,不会干扰新连接。 第二个原因是确保可靠实现 TCP 全双工终止连接。关闭连接的四次挥手中, 最终的 ACK 是由主动关闭方发出,如果这个 ACK 丢失,对端将重发 FIN,如果主动关闭方不维持 TIME_WAIT 直接进入 CLOSED 状态,则无法重传 ACK,被动关闭方因此不能及时可靠释放。1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能够到达对端,1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达。 @@ -79,6 +79,10 @@ FIN 同 SYN 报文一样,不管是否携带数据,FIN 段都需要消耗一 #### 重传机制 +永远记住,ACK 是表示这之前的包都已经全部收到了。 + +快速重传的含义是:当发送端收到 3 个或以上重复 ACK,就意识到之前发的包可能丢了,于是马上进行重传,不用傻傻的等到超值再重传。 + #### 滑动窗口 TCP 会把要发送的数据放入发送缓冲区,接收到的数据放入接收缓冲区,应用程序会不停的读取缓冲区的内容进行处理。流量控制做的事情就是,如果接收缓冲区已满,发送端应该停止发送数据,那发送端怎么知道接收端缓冲区是否已满呢?为了控制发送端的速率,接收端会告知客户端的自己的接收窗口(rwnd),TCP 在收到数据包回复的 ACK 包里会带上自己接收窗口的大小,客户端需要根据这个值调整自己的发送策略。 @@ -99,7 +103,7 @@ TCP 会把要发送的数据放入发送缓冲区,接收到的数据放入接 在连接建立之初,应该发多少数据才是合适的呢?其实很难,因为不知道对端的处理能力以及途径的网络状况,所以在最初时,发送的数据量很小,但随着时间的推移,拥塞窗口会慢慢的递增,这种机制被称为慢启动。cwnd 每经过一个 RTT,就会变为之前的两倍。 -但是也不可能无止境的指数级增长下去,否则就失控了,当 cwnd 超过慢启动阈值时,就启动拥塞避免算法,拥塞窗口按线性增长。即没经过一个 RTT,cwnd 增加 1. +但是也不可能无止境的指数级增长下去,否则就失控了,当 cwnd 超过慢启动阈值时,就启动拥塞避免算法,拥塞窗口按线性增长。即每经过一个 RTT,cwnd 增加 1. 快速重传的含义是:当接收端收到一个不按序到达的数据段时,TCP 立刻发送一个 1 个重复 ACK,当发送端收到 3 个或以上重复 ACK 时,就意识到之前发的包可能丢了,于是马上进行重传,不用傻等到重传定时器超时在重传。