Java面试考点:TCP三次握手和四次挥手你真的懂?

△三次握手建立接,究竟是什么情况?

TCP是基于连接的,所以在传输数据前需要建立连接。

  TCP在传输上是双工传输,不区分Client端和Server端,为了便于理解,我们把主动发起建连请求的一端称作Client端,把被动建立连接的一端称为Server端。

TCP三次握手

  建连的时序是从上到下,左右两边的绿色字分别代表Client端与Server端当时的连接状态。

  首先建立连接前需要Server端先监听端口,因此Server端建立连接前的初始状态就是LISTEN状态,这时Client端准备建立连接,先发送一个SYN同步包,发同步包后,Client端的链接状态变为了SYN_SENT状态。

  Server端收到SYN后,同意建立连接,会向Client端回复一个ACK。

  由于TCP是全双工传输,Server端也会同时向Client端发送一个SYN,申请Server向Client端发送一个SYN,申请Server向Client方向建立连接。发送完ACK和SYN后,Server的连接状态就变成了SYN_RCVD。

  Client收到Server的ACK候,Client端的连接状态就变成了ESTABLISHED状态,同时Client向Server端发送ACK,回复Server端的SYN请求。

  Server端收到Client端的ACK候,Server端的连接状态也变成了ESTABLISHED状态,此时建连完成,双方随时可以进行数据传输。

在面试的时候你需要掌握:
  ①明白三次握手是为了建立双向连接。
  ②记住Client端和Server端的连接状态变化。

在面试的时候这样拓展可以加分:

SYN洪水攻击发生的原因:Server端收到Client端SYN请求后,发送了ACK和SYN,但是Client不进行恢复,导致Server端大量的连接处于SYN_RCVD状态,进而影响其他正常请求的建连。可以设置top_synack_retries = 0 加快半连接回收速度,或者调大tcp_max_syn_backlog来应对少量的SYN洪水攻击。

△四次挥手断连,到底是啥?

TCP四次挥手

  TCP连接的关闭,通信双方都可以先发起,暂时把先发起的一方看作Client,从图中看出,通信中Client和Server两端的连接都是ESTABLISHED状态,然后Client先主动发起了关闭连接请求,Client向Server发送了一个FIN包,表示Client端以及没有数据要发送了,然后Client进入FIN_WAIT_1状态。

  Server端收到FIN后,返回ACK,然后进入CLOSE_WAIT状态。此时Server属于半关闭状态,因为此时Client向Server方向已经不会发送数据了,可是Server向Client端可能还有数据要发送。

  当Server端数据发送完毕后,Server端会向Client端发送FIN,表示Server端也没有数据要发送了,此时Server进入LAST_ACK状态,就等待Client的应答就可以关闭连接了。

  Client端收到Server端FIN后,回复ACK,然后进入TIME_WAIT状态。TIME_WAIT状态下需要等待2倍的最大报文段生存时间,来保证连接的可靠关闭,之后才会进入CLOSE关闭状态。而Server收到ACK后进进入了CLOSE状态。

这里面试官可能会问:为什么需要等待两倍最大报文段生存时间之后再关闭连接?
原因如下:
  ①保证TCP协议全双双工连接能够可靠关闭。
  ②保证这次连接的重复数据段从网络中消失,防止端口被重用时可能产生数据混淆。

在面试时候你可以这样拓展:
  说说实际应用中有可能遇到大量Socket处在TIME_WAIT或者CLOSE_WAIT状态的问题。一般开启TCP_TW_REUSE和TCP_TW_RECYCLE能够加快TIME_WAIT的Sockets的回收。而大量的CLOSE_WAIT可能是被动关闭的一方存在代码BUG,没有正确关闭链接导致的。

所以,建连三次握手而断连需要四次的原因,你知道了吗?

  从交互流程可以看出,无论是建连还是断连,都是需要在两个方向进行的。
只不过建连时,Server的SYN和ACK合并为一次发送,而断连时,两个方向上发送停止时间可能不同,所以不能合并发送FIN和ACK。

推荐阅读更多精彩内容