TCP连接过程,三次握手和四次挥手,为什么?
连接阶段(三次握手):
- 创建套接字
Socket
,服务器会在启动的时候就创建好,客户端是在需要访问服务器的时候创建套接字 - 然后发起连接操作,其实就是Socket的
connect
方法 - 这时候客户端会生成一个TCP数据包。这个数据包的TCP头部有三个重要信息:
SYN、SEQ、ACK
。
SYN,同步序列编号,是TCP/IP建立连接时使用的握手信号,如果这个值为1就代表是连接消息。
SEQ,数据包序号,是发送数据的一个顺序编号。
ACK,确认号,是接收数据的一个顺序编号。
- 所以客户端就生成了这样一个数据包,其中头部信息的
SYN
设置为1,代表连接。SEQ
设置一个随机数,代表初始序号,比如100。ACK
没有设置,因为是第一次发送数据,不需要ACK
。 - 然后服务器端收到这个消息,知道了客户端是要来连接的
(SYN=1)
,知道了传输数据的初始序号(SEQ=100)
。 - 服务器端也要生成一个数据包发送给客户端,这个数据包的TCP头部会包含
三个值
:表示我也要连接你的SYN(SYN=1)
,我已经收到了你的上个数据包的确认号ACK(ACK=SEQ+1=101)
,以及服务器端随机生成的一个序号SEQ(比如SEQ=200)
。 - 最后客户端收到这个消息后,表示客户端到服务器的连接是无误了,然后再发送一个数据包表示也确认收到了服务器发来的数据包,这个数据包的头部就主要就是一个
ACK值(ACK=SEQ+1=201)
。 - 至此,连接成功,三次握手结束,后面数据就会正常传输,并且每次都要带上TCP头部中的
SEQ和ACK值
。
这里有个问题是关于为什么需要三次握手
?
最主要的原因就是需要通信双方都确认自己的消息被准确传达过去了。
A发送消息给B,B回一条消息表示我收到了,这个过程就保证了A的通信能力。
B发送消息给A,A回一条消息表示我收到了,这个过程就保证了B的通信能力。
也就是四条消息能保证双方的消息发送都是正常的,其中B回消息和B发消息,可以融合为一次消息,所以就有了三次握手
。
数据传输阶段:
数据传输阶段有个改变就是ACK确认号
不再是SEQ+1
了,而是SEQ+数据长度
。例如:
- A发送给B的数据包(SEQ=100,长度=1000字节)
- B回给A的数据包(ACK=100+1000=1100)
这就是一次数据传输的头部信息,ACK
代表下个数据包应该从哪个字节开始所以等于上个数据包的SEQ+长度,SEQ就等于上个数据包的ACK。
当然,TCP通信是双向的,所以实际数据每个消息都会有SEQ和ACK
:
- A发送给B的数据包(ACK=200,SEQ=100,长度=1000字节)
- B回给A的数据包(ACK=100+1000=1100,SEQ=上一个数据包的ACK=200,长度=500字节)
- A发送给B数据包(SEQ=1100,ACK=200+500=700)
断开阶段(四次挥手):
和连接阶段一样,TCP头部也有一个专门用作关闭连接的值叫做FIN。
-
客户端准备关闭连接,会发送一个
TCP数据包
,头部信息中包括(FIN=1代表要断开连接)
。 -
服务器端收到消息,回复一个数据包给客户端,头部信息中包括
ACK确认号
。但是此时服务器端的正常业务可能没有完成,还要处理下数据,收个尾。 -
客户端收到消息。
-
服务器继续处理数据。
-
服务器处理数据完毕,准备关闭连接,会发送一个
TCP数据包
给客户端,头部信息中包括(FIN=1代表要断开连接) -
客户端端收到消息,回复一个数据包给服务器端,头部信息中包括
ACK确认号
。 -
服务器收到消息,到此服务器端完成连接关闭工作。
-
客户端经过一段时间(2MSL),自动进入
关闭状态
,到此客户端完成连接关闭工作。
MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
这里有个问题是关于为什么需要四次挥手?
A发送断开消息给B,B回一条消息表示我收到了,这个过程就保证了A断开成功。
B发送断开消息给A,A回一条消息表示我收到了,这个过程就保证了B断开成功。
其实和连接阶段的区别就在于,这里的B的确认消息和断开消息不能融合
。因为A要断开的时候,B可能还有数据要处理要发送,所以要等正常业务处理完,在发送断开消息。