这节课,我们来简单描述下网络断开的过程。
1.四次挥手
毫无疑问,收发数据结束的时间点应该是应用程序判断所有数据都已经发送完毕的时候。这时,发送数据完成的一方会发起断开过程。也就是说,客户端和服务器都可以发起断开连接请求,这一点与网络连接建立过程不同。
这里我们以服务器一方发起断开过程为例来进行讲解:
- 首先,服务器的协议栈(也就是调用socket库)会生成包含断开信息的TCP头部,也就是将TCP头部中的标志位FIN比特位设置位1。
- 接下来,协议栈委托IP模块向客户端发送数据。同时,服务器的套接字中也会记录下断开操作的相关信息。
- 接下来就轮到客户端了。当收到服务器发来的FIN=1的TCP头部时,客户端的协议栈就会将自己的套接字标记为断开操作状态。然后回复一个ACK包。
上面是完成了服务端的断开请求。
等待一段时间(有些数据还在网络上进行传输),当客户端接收完数据后,同样会发起一个FIN=1的TCP包,然后委托IP模块发送给服务器。一段时间后,服务器就会返回ACK号。至此,客户端和服务端的通信就全部结束了。
那么,就有同学会问了,为什么连接的时候是"三次握手",到了断开操作时就变成了"四次挥手"呢?
其实呢,连接和断开的都是双方进行控制信息的交换过程,也是双方都进行一次"一发一回"的过程。只不过,连接的时候服务器将应答和请求拟合成了一条消息。断开连接不能这么做,是因为网络上还有未接收的数据。
2.删除套接字
双方通信完成后,对应的套接字也就不会再使用了,这时候我们就可以删除套接字了。不过套接字不会立刻被删除,而是会等待一段时间之后再被删除。这又是为什么?
主要是为了防止误操作,引发误操作的原因很多。比如我们进行下面的操作步骤:
(1).客户端发送FIN。
(2).服务器返回ACK号。
(3).服务器发送FIN。
(4).客户端返回ACK号。
如果最后客户端返回的ACK号丢失了,结果会怎么样呢?我们都知道TCP有重发机制,会再次反宋FIN请求,但是如果此时客户端的套接字被删除并被分配给了其他的程序,那么这个程序收到了服务器发送来的FIN信号,就会响应请求,关闭连接。这样就会造成不可预估的错误。一般套接字会在大约几分钟后进行删除。
3.整个通信过程
我们用下面的图来总结下网络连接的整个过程:
- 首先,是网络连接建立的过程,使用"三次握手"机制来完成控制信息的交换,这些控制信息分为两种,一种是各种头部信息,一种是保存在套接字里的信息。
- 其次,是网络数据收发过程,使用socket中的read(…)/write(…)接口来完成数据的收发。
- 最后,是断开网络的过程,使用了"四次挥手"机制以及延迟删除套接字的机制完成通信的断开。