您的当前位置:首页正文

java---TCP三次握手、四次挥手详解

来源:华佗健康网


一、TCP三次握手

1.第一次握手:客户端请求建立连接,向服务端发送一个同步报文(SYN=1),同时选择一个随机数 SN(Sequence Numer) = x 作为初始序列号,并进入SYN_SENT状态,等待服务器确认。

2.第二次握手:服务端收到连接请求报文后,如果同意建立连接,则向客户端发送同步确认报文(SYN=1,ACK=1),确认号为 ASN = x + 1,同时选择一个随机数 SN= y 作为初始序列号,此时服务器进入SYN_RCVD状态。

3.第三次握手:客户端收到服务端的确认后,向服务端发送一个确认报文(ACK=1),确认号为 ASN = y + 1,序列号为 SN = x + 1,客户端和服务器进入ESTABLISHED状态,完成三次握手。

1.标志位角度

2.序列号角度

对于ISN是自动生成的,所以TCP在三次握手的阶段会双方同步一些信息。

对于初始的确认序列号一般都是0, 所以ASN = 0。

3.状态转换角度

codeC 代码:开始建立TCP请求

codeA代码:启动服务器

ServerSocket serverSocket  = new ServerSocket("目标主机进程绑定的端口")

codeB代码: 监听在端口上

Socekt  socket = serverSocket.accept(); // 会阻塞,直到建立TCP连接

4. 为什么是三次握手,而不是两次

1.防止已过期的连接请求报文突然又传送到服务器,因而产生错误和资源浪费。

假设是两次握手建立连接:假设客户端发送 A 报文段请求建立连接,由于网络原因造成 A 暂时无法到达服务器,服务器接收不到请求报文段就不会返回确认报文段。

客户端在长时间得不到应答的情况下重新发送请求报文段 B,这次 B 顺利到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,客户端在收到确认报文后也进入 ESTABLISHED 状态,双方建立连接并传输数据,之后正常断开连接。

此时姗姗来迟的 A 报文段才到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,但是已经进入 CLOSED 状态的客户端无法再接受确认报文段,更无法进入 ESTABLISHED 状态,这将导致服务器长时间单方面等待,造成资源浪费。

2.三次握手才能让双方均确认自己和对方的发送和接收能力都正常。

第一次握手:客户端只是发送请求报文段,什么都无法确认,而服务器可以确认自己的接收能力和对方的发送能力正常;

第二次握手:客户端可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;

第三次握手:服务器可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;

可见三次握手才能让双方都确认自己和对方的发送和接收能力全部正常,才可以进行正常的通信。

3.告知对方自己的初始序号值,并确认收到对方的初始序号值。

TCP 实现了可靠的数据传输,原因之一就是 TCP 报文段中维护了序号字段和确认序号字段,通过这两个字段双方都可以知道在自己发出的数据中,哪些是已经被对方确认接收的。这两个字段的值会在初始序号值得基础递增,如果是两次握手,只有发起方的初始序号可以得到确认,而另一方的初始序号则得不到确认。

5.TCP协议握手阶段缺陷---SYN泛洪攻击

简略的来说,就是向服务器发送大量的半连接请求,耗费CPU资源和内存资源。

1.原理

1.在三次握手过程中,服务器发送(syn/ack)包(第二个包)之后、收到客户端的(ack)包(第三个包)之前的 TCP 连接称为半连接(half-open connect),此时服务器处于syn_rcvd(等待客户端响应)状态。如果接收到客户端的(ack),则 TCP 连接成功,如果未接受到,则会超时重传

3.这些伪造的(syn) 包将长时间占用未连接队列,影响了正常的 syn,导致目标系统运行缓慢、网络堵塞甚至系统瘫痪。

2.防范

1.通过防火墙、路由器等过滤网关防护。

2.通过加固 TCP/IP 协议栈防范,如增加最大半连接数,缩短超时时间。

6.三次握手阶段,最后一次ACK包丢失

服务器端

1.第三次的ACK在网络中丢失,那么服务端该TCP连接的状态为SYN_RCVD,并且会根据TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便客户端重新发送ACK包。

2.如果重发指定次数之后,仍然未收到客户端的ACK应答,那么一段时间后,服务端自动关闭这个连接。

客户端

客户端认为这个连接已经建立,如果客户端向服务端发送数据,服务端将以RST包(Reset,标示复位,用于异常的关闭连接)响应。此时,客户端知道第三次握手失败。

二、TCP四次挥手

1.四次挥手过程

1.第一次挥手:客户端向服务端发送连接释放报文(FIN=1),主动关闭连接,同时等待服务端的确认。

2.第二次挥手:服务端收到连接释放报文后,立即发出确认报文(ACK=1)。

这表示客户端已经没有数据发送了,但是服务端可能还要给客户端发送数据。

3.第三次挥手:服务端向客户端发送连接释放报文(FIN=1),主动关闭连接,同时等待客户端的确认。

4.第四次挥手:客户端收到服务端的连接释放报文后,立即发出确认报文(ACK=1)。

此时,客户端就进入了 TIME_WAIT  状态。注意此时客户端到 TCP 连接还没有释放,必须经过 2*MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态。而服务端只要收到客户端发出的确认,就立即进入 CLOSED 状态。可以看到,服务端结束 TCP 连接的时间要比客户端早一些。

过程如下图所示:

主动关闭方依次会经过以下的阶段:

FIN_WAIT1 -> FIN_WAIT2 -> TIME_WAIT -> CLOSE

被动关闭方会依次经过以下的阶段:

CLOSE_WAIT -> LAST_ACK -> CLOSE

2.为什么客户端 TIME_WAIT 需要等待 2MSL

MSL : Maximum Segment Live 表示的报文段在网络中最大的存活时间。

1.确保 ACK 报文能够到达服务端,从而使服务端正常关闭连接。

第四次挥手时,客户端第四次挥手的 ACK 报文不一定会到达服务端。服务端会超时重传 FIN/ACK 报文,此时如果客户端已经断开了连接,那么就无法响应服务端的二次请求,这样服务端迟迟收不到 FIN/ACK 报文的确认,就无法正常断开连接。

MSL 是报文段在网络上存活的最长时间。客户端等待 2MSL 时间,即「客户端 ACK 报文 1MSL 超时 + 服务端 FIN 报文 1MSL 传输」,就能够收到服务端重传的 FIN/ACK 报文,然后客户端重传一次 ACK 报文,并重新启动 2MSL 计时器。如此保证服务端能够正常关闭。

如果服务端重发的 FIN 没有成功地在 2MSL 时间里传给客户端,服务端则会继续超时重试直到断开连接。

2.防止已失效的连接请求报文段出现在之后的连接中。

TCP 要求在 2MSL 内不使用相同的序列号。客户端在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。

3.CLOSE_WAIT 与 TIME_WAIT

CLOSE_WAIT

1.出现在被动关闭方一侧

2.出现在挥手阶段

3.如果出现大量的 close_wait 可能是服务器进程漏了写 socket.close() 操作。

TIME_WAIT

1.一般出现在主动关闭方一侧

2.TIME_WAIT 需要等待 2MSL,在大量短连接的情况下,TIME_WAIT会太多,这也会消耗很多系统资源。


总结

加油偶~~

因篇幅问题不能全部显示,请点此查看更多更全内容