TCP三次握手和四次挥手

手麻了。

TCP三次握手

最开始服务端和客户端均处于closed状态,然后服务端主动开启LISTEN准备接收报文。

第一次握手

客户端将TCP首部中的SYN置为1,并且初始化一个随机序列号client_isn。随后将这个SYN报文(包含随机序列号)发送给服务端,然后进入SYN-SENT状态。这次握手告知服务端,客户端想要建立TCP连接。

第二次握手

服务端接收到客户端发送的SYN报文后,将TCP首部中的ACK置为1,同时将其中的确认应答号变为cilent_isn+1,生成ACK报文。然后初始化一个自己的随机序列号server_isn,并生成SYN报文。服务端同时将ACK SYN两个报文一并发送给客户端,然后进入SYN-REVD状态。此次握手是告诉客户端服务端知晓了需要建立TCP连接,请根据返回的信息进行应答正式建立连接。

第三次握手

客户端接受到服务端发送的两个报文,通过ACK报文确认确实是自己想要建立连接的那台服务器。然后根据server_isn生成确认应答号以及ACK报文,并且将ACK报文发送给服务端,然后进入ESTABLISHED状态。服务端接受到ACK报文后就进入ESTABLISHED状态。双方都进入这个状态后TCP连接正式建立完毕,可以开始发送HTTP请求了。此次握手告诉服务器客户端已经就绪,可以进行正式的连接建立。

灵魂拷问:为啥要三次握手,两次不行吗?

两次握手一般就是放弃最后一个握手,带来的最大的问题就是建立历史连接。比如客户端发送第一次SYN报文后就宕机了,正好这个发送的报文又遇到了网络堵塞,然后我重启客户端又发送一次SYN报文。服务端这边旧报文比新报文先抵达了,在两次握手的情况下,服务端每接收一个SYN报文就要建立一个连接,新旧报文明明是要建立相同的链接,但是却各自建立了相同的连接,造成了资源的浪费。

三次握手就能避免这个问题。还是上面的问题,建设两次SYN报文的cilent_isn分别是90和100,客户端发送第二次报文后,期望得到的确认号是101,但是实际会得到91,此时客户端发现确认号有问题就会发送RST告诉服务端,这个90序列号的连接需要释放,不要建立它的连接。

TCP四次挥手

开始时双方均处于ESTABLISHED状态,两边都可以发起断开连接的请求。下面以客户端为例介绍。

第一次挥手

客户端发送FIN报文到服务端,然后进入FIN_WAIT_1状态。服务端接受到FIN报文之后进入close_WAIT状态。此次挥手告诉服务端,客户端想要断开连接。

第二次挥手

服务器接收到FIN报文,生成一个ACK报文发送给客户端。客户端进入FIN_WAIT2状态。此次挥手告诉客户端,服务端已经明白了想要断开连接的请求。但是服务端可能还要处理一些数据,或者发送一些数据给客户端,暂时还不要断开连接。

第三次挥手

服务器在上一步中处理完数据后,发送一个FIN报文,进入LAST_ACK状态。此次挥手告诉客户端数据处理完毕,可以正式断开连接了。

第四次挥手

客户端接受到服务器的FIN报文,明白可以正式断开连接。客户端发送ACK报文,然后进入TIME_WAIT状态,之后会自动关闭。服务端接受到这个ACK报文之后就知道客户端那边已经确认可以关闭了,于是直接关闭连接。

灵魂拷问2.0:能不能只有三次挥手?

也不是不行,三次挥手就是将第二次和三次的ACK FIN一起发送。此时表示,客户端申请断开连接的时候,服务端这边已经没有需要处理和发送的数据了,所以这两个报文就可以一起发送了。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容