TCP 协议灵魂问题,巩固你的网路底层基础( 二 )


第三次握手的时候 , 客户端已经处于ESTABLISHED状态 , 并且已经能够确认服务器的接收、发送能力正常 , 这个时候相对安全了 , 可以携带数据 。
同时打开会怎样?
如果双方同时发SYN报文 , 状态变化会是怎样的呢?
这是一个可能会发生的情况 。
状态变迁如下:
![![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9HjdUSFf-1613660286518)(data:image/gif;,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]](https://img-blog.csdnimg.cn/20210218230145936.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25ldHdvcmt0cA==,size_16,color_FFFFFF,t_70)
在发送方给接收方发SYN报文的同时 , 接收方也给发送方发SYN报文 , 两个人刚上了!
发完SYN , 两者的状态都变为SYN-SENT 。
在各自收到对方的SYN后 , 两者状态都变为SYN-REVD 。
接着会回复对应的ACK+SYN , 这个报文在对方接收之后 , 两者状态一起变为ESTABLISHED 。
这就是同时打开情况下的状态变迁 。
003:说说TCP四次挥手的过程
过程拆解

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
刚开始双方处于ESTABLISHED状态 。
客户端要断开了 , 向服务器发送FIN报文 , 在TCP报文中的位置如下图:

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
发送后客户端变成了FIN-WAIT-1状态 。 注意,这时候客户端同时也变成了half-close(半关闭)状态 , 即无法向服务端发送报文 , 只能接收 。
服务端接收后向客户端确认 , 变成了CLOSED-WAIT状态 。
客户端接收到了服务端的确认 , 变成了FIN-WAIT2状态 。
随后 , 服务端向客户端发送FIN , 自己进入LAST-ACK状态 ,
客户端收到服务端发来的FIN后 , 自己变成了TIME-WAIT状态 , 然后发送ACK给服务端 。
注意了 , 这个时候 , 客户端需要等待足够长的时间 , 具体来说 , 是2个MSL(MaximumSegmentLifetime , 报文最大生存时间),在这段时间内如果客户端没有收到服务端的重发请求 , 那么表示ACK成功到达 , 挥手结束 , 否则客户端重发ACK 。
等待2MSL的意义
如果不等待会怎样?
如果不等待 , 客户端直接跑路 , 当服务端还有很多数据包要给客户端发 , 且还在路上的时候 , 若客户端的端口此时刚好被新的应用占用 , 那么就接收到了无用数据包 , 造成数据包混乱 。 所以 , 最保险的做法是等服务器发来的数据包都死翘翘再启动新的应用 。
那 , 照这样说一个MSL不就不够了吗 , 为什么要等待2MSL?
1个MSL确保四次挥手中主动关闭方最后的ACK报文最终能达到对端1个MSL确保对端没有收到ACK重传的FIN报文可以到达这就是等待2MSL的意义 。
为什么是四次挥手而不是三次?
因为服务端在接收到FIN,往往不会立即返回FIN,必须等到服务端所有的报文都发送完毕了 , 才能发FIN 。 因此先发一个ACK表示已经收到客户端的FIN , 延迟一段时间才发FIN 。 这就造成了四次挥手 。
如果是三次挥手会有什么问题?
等于说服务端将ACK和FIN的发送合并为一次挥手 , 这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端 , 从而让客户端不断的重发FIN 。
同时关闭会怎样?
如果客户端和服务端同时发送FIN , 状态会如何变化?如图所示:

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
004:说说半连接队列和SYNFlood攻击的关系
【TCP 协议灵魂问题,巩固你的网路底层基础】三次握手前 , 服务端的状态从CLOSED变为LISTEN,同时在内部创建了两个队列:半连接队列和全连接队列 , 即SYN队列和ACCEPT队列 。
半连接队列
当客户端发送SYN到服务端 , 服务端收到以后回复ACK和SYN , 状态由LISTEN变为SYN_RCVD , 此时这个连接就被推入了SYN队列 , 也就是半连接队列 。
全连接队列
当客户端返回ACK,服务端接收后 , 三次握手完成 。 这个时候连接等待被具体的应用取走 , 在被取走之前 , 它会被推入另外一个TCP维护的队列 , 也就是全连接队列(AcceptQueue) 。
SYNFlood攻击原理
SYNFlood属于典型的DoS/DDoS攻击 。 其攻击的原理很简单 , 就是用客户端在短时间内伪造大量不存在的IP地址 , 并向服务端疯狂发送SYN 。 对于服务端而言 , 会产生两个危险的后果:
处理大量的SYN包并返回对应ACK,势必有大量连接处于SYN_RCVD状态 , 从而占满整个半连接队列 , 无法处理正常的请求 。 由于是不存在的IP , 服务端长时间收不到客户端的ACK , 会导致服务端不断重发数据 , 直到耗尽服务端的资源 。如何应对SYNFlood攻击?