三次握手,四次挥手

2020-03-06  本文已影响0人  爱读书的夏夏

https://blog.csdn.net/qq_38950316/article/details/81087809

https://baijiahao.baidu.com/s?id=1614404084382122793&wfr=spider&for=pc

  1. 同步SYN:Synchronize Sequence Numbers
  2. 确认ACK:Acknowledgement
  3. 终止FIN:finish
  4. RST:RESET

TCP状态:

  1. LISTEN:侦听来自远方的TCP端口的连接请求
  2. SYN-SENT:再发送连接请求后等待匹配的连接请求(如果有大量这样的状态包,检查是否中招了)
  3. SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认(如有大量此状态,估计被flood攻击了)
  4. ESTABLISHED:代表一个打开的连接
  5. FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认
  6. FIN-WAIT-2:从远程TCP等待连接中断请求
  7. CLOSE-WAIT:等待从本地用户发来的连接中断请求
  8. CLOSING:等待远程TCP对连接中断的确认
  9. LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认(不是什么好东西,此项出现,检查是否被攻击)
  10. TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认
  11. CLOSED:没有任何连接状态

三次握手:


三次握手

四次挥手:


四次挥手

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

【问题3】为什么不能用两次握手进行连接?

答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

问题一 S给C的确认丢失:
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C给S的应答分组在传输中被丢失的情况下,C将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

问题二 C给S的请求失效后重新到达S:
假设一下如果没有第三次握手,而是两次握手后我们就认为连接成功了,那么会发生什么?第三次握手是为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误。
譬如发起请求遇到类似这样的情况:客户端发出去的第一个连接请求由于某些原因在网络节点中滞留了导致延迟,直到连接释放的某个时间点才到达服务端,这是一个早已失效的报文,但是此时服务端仍然认为这是客户端的建立连接请求第一次握手,于是服务端回应了客户端,第二次握手。
如果只有两次握手,那么到这里,连接就建立了,但是此时客户端并没有任何数据要发送,而服务端还在傻傻的等候佳音,造成很大的资源浪费。所以需要第三次握手,只有客户端再次回应一下,就可以避免这种情况。

   对于这种情况,我现在有些怀疑:报文里没有有效时间吗?如果超时失效,那么及时再次达到S,也将被认为是失效的吧?除非是没有超时,但是没有超时,C又怎么会重新发送链接请求呢? 或者是C发起一个链接请求以后,C自己挂掉了,所以这个链接请求其实已经失效了,但是已经发出去的数据包并不知道应该被设置为失效,所以就如期到达服务器端了。嗯,应该是这种情况。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

【问题5】长时间处于CLOSE_WAIT状态的原因是什么?
因为对方主动关闭后,我方还在持续的读(不知道是不是有写),就会导致该链接在我方的状态持续停留在CLOSE_WAIT。 在一种场景下会发生这种问题,就是没有关闭socket。我之前写过一个压测的脚本,发送请求给服务端,但是最终没有写关闭socket的代码,然后就发现本地的TCP状态都停留在CLOSE_WAIT的状态。解决方法为检测到对方关闭后,我方也关闭socket。

上一篇下一篇

猜你喜欢

热点阅读