简谈TCP连接——三次握手与四次挥手
基本概念
在三次握手与四次挥手的过程中,会出现一些相关概念。为了便于后文的阅读,我先把相关的解释罗列在此。
SYN:SYN是Synchronize(同步)的缩写,意思是通过告知初始序号使通信双方保持步调一致,以便完成后续的数据收发检查。
seq(序号初始值):首先,我们得知道,HTTP请求消息一般不会太长,一个网络包就能装的下,但如果出现了数据量比较大的情况,TCP模块就会在发送数据前先将数据按照一定长度进行拆分,拆分出来的每块数据放进单独的网络包中。在拆分网络包时,TCP模块会先计算好每一块数据相当于从头开始的第几个字节。而序号就是用在这里的。当然,在实际的通信中,为了安全防范,序号并不是从1开始的,而是需要用随机数计算出一个初始值。
ACK号:因为在通信过程中初始值有可能丢失,因此,收据接收方在收到序号初始值时还需要根据该初始值计算出相应的ACK号返回给数据发送方。设置ACK号时,除了需要设置ACK号字段的值,还需要将控制位的比特值设为1(表有效)。
三次握手
文字描述只作大概描述,可结合图片进行深入理解。
- 第一次握手:客户端计算出与从客户端到服务器方向通信相关的序号初始值(seq=x),并将这个值发给服务器。
- 第二次握手:初始值在通信过程中有可能丢失,因此服务器需要根据这个初始值计算出ACK号。同时,服务器也需要计算出从服务器到客户端方向通信相关的序号初始值(seq=y)。然后服务器将自身到客户端通信的序号初始值与ACK号返回给客户端。
- 第三次握手:客户端根据服务器发来的初始值计算出ACK号并返回给服务器。到此,连接便简历成功了。
四次挥手
在数据收发结束后,数据发送完毕的一方会发起断开过程。而断开时机的判断是有由应用程序做出的,协议栈在设计上允许任何一方先发起断开的过程。在这里,我们以服务器一方发起断过程为例来进行讲解。
- 第一次挥手:服务器的协议栈会生成包含断开信息的TCP头部,具体来说就是将控制位中的FIN比特设为1,并发送给客户端。同时,服务器的套接字也会记录下断开操作的相关信息。
- 第二次挥手:当客户端收到服务器发来的FIN为1的TCP头部时,客户端的协议栈会将自己的套接字标记为进入断开操作状态。然后,为了告知服务器已收到FIN为1的包,客户端会向服务器返回一个ACK号。这些操作完成后,协议栈就可以等待应用程序来取数据了。(应用程序也有可能在收到FIN为1的包之前就来取数据,这时读取数据的操作会被挂起,等待FIN包到达再继续执行)
- 第三次挥手:当应用程序将数据读取完毕后,客户端应用程序会调用close来结束数据收发操作,这时客户端协议栈也会和服务器一样,生成一个FIN比特为1的TCP包返回给服务器。
- 第四次挥手:一段时间后,服务器就会返回ACK号给客户端。到这里,客户端和服务器的通信就全部结束了。
到此,三次握手与四次挥手也算是讲了个大概了。至于在这其中涉及到的其他细节点,本文中就不展开来写了。
参考