TCP三次握手与四次挥手
三次握手?
什么是三次握手?
【TCP三次握手与四次挥手】一般情况下,连接是由客户端向服务端发起的。
第一次,客户端发送一个TCP数据报并将SYN同步位置为1,表示要建立连接,此时客户端会从CLOSED状态变为SYN_SEND状态;
第二次是服务端向客户端发送ACK,并且也将SYN置为1,一是表示自己收到了客户端建立连接的请求,并且从LISTEN状态变为SYN_RCVD,二是表示自己要建立连接;
当客户端收到服务端的ACK + SYN后,便会处于ESTABLISHED状态,并且发送第三次握手,表示自己收到了客户端的SYN。当服务端收到客户端的ACK后,便会从SYN_RCVD状态变为ESTABLISHED状态。
此时,双方的连接才算真正的建立。
为什么需要三次握手,而不是两次握手或者四次握手?
1.双方之所以进行多次握手,本质上还是因为信道是不可靠的。
由于TCP本身的要求是可靠连接,因此,客户端和服务端都必须确认,对方的收发能力都是正常的。因此,当第二次握手结束,客户端就可以确保服务端的收发能力正常,建立起连接,但是,服务端只能确保客户端的发送能力正常,因此必须等收到第三次握手的ACK后才会建立连接。
理论上四次五次都可以,但是三次就可以保证,所以是三次握手。
2.最好是奇数次握手
在socket编程时,服务端一般是先listen再accept。也就是说,发起连接的都是客户端。
谁发送最后的ACK,谁就会先建立连接。如果是偶数次,那么最后一次发送ACK的就是服务端。一般情况下,服务器比客户端的数量是1:n,众所周知,维护连接是需要付出时间和空间成本的,比如需要在内核建立相关结构体,如果服务器建立连接而客户端未建立,那么服务端可能会有多个空连接,这其实是不利于服务器的。
奇数次的握手是一种成本转移,即便出现空连接的现象,成本也会分摊在多个客户端身上,而不至于给服务端太大压力。
四次挥手
什么是四次挥手?
四次挥手与三次握手对应,是断开连接的过程。
由于双方之前进行了大量数据的交互,因此通过发送与确认机制就可以保证双方连接的断开。
首先断开的一方会发送FIN,便会处于FIN_WAIT_1状态,只要收到ACK后,便会处于FIN_WAIT_2状态。表示自己关闭了发送缓冲区,不再发送数据,但依然具有接受数据的能力。
而另一方收到FIN后,便会处于CLOSE_WAIT状态,即半关闭状态。它还可以继续发送数据,当数据发送完毕后,又会发送FIN,当收到ACK后便关闭自己的发送缓冲区。
这就是四次挥手。
为什么是四次?
我们在写客户端或者服务端时,都有一个close(fd),即关闭文件描述符的操作。每一个close代表的就是两次挥手。
如果说只有两次,也就是说一方在执行代码逻辑时没有执行close(fd),第一,会造成文件描述符泄露,第二,会发现这一端存在CLOSE_WAIT状态的连接,即半关闭状态。这种状态并没有释放连接相关的数据和结构体,其实也会造成内存泄漏。
为什么四次挥手后,主动断开连接的一方会先进入TIME_WAIT状态?
四次挥手的前三次,由于超时重传机制的存在,可以保证一定被对方收到,但是最后一次的ACK,是可能丢失的。如果四次挥手后,主动断开的一方直接CLOSED,那么将无法保证最后一个ACK被对方收到。
如果ACK丢失,对方就会重新发送FIN,如果处于CLOSED状态,将不会收到FIN,使得对方长时间处于LAST_ACK状态,并且多次发送FIN消耗资源。因此,通过TIME_WAIT,可以较大概率地保证最后一个ACK被对方收到。
另一个原因是可以保证信道上的数据尽可能的消散,防止断开连接后又立马重新建立连接后,产生的数据错误等问题。
为什么TIME_WAIT是2MSL?
2MSL是两个最大报文段寿命,ACK丢失最多是一个MSL,再次收到重传的FIN最多是一个MSL,因此2MSL可以尽可能的保证在CLOSE之前收到对方重传的FIN。
推荐阅读
- Java学习笔记|java网络编程基础详解三之TCP协议的3次握手与4次挥手过程详解
- 计算机网络|TCP网络编程模型从入门到实战基础篇,单服务器单个用户非并发版本
- 计算机网络|网络入门基础模型, 网络大体框架, TCP/IP协议栈, 各种局域网和广域网刨析 (以图解的方式推开网络大门)
- TCP/IP|【TCP/IP】TCP的三次握手和四次挥手
- 三次握手|三次握手 & 四次挥手
- TCP三次握手原理
- C++|C++ Socket实现TCP与UDP网络编程
- Java|记一次TCP TIME_WAIT引发的血案
- 快24岁了,没什么目标(不才的21年年终总结)
- 云计算的三次变革浪潮