TCU运输连接管理

TCP连接建立之三次握手和四次挥手

Posted by odin on March 26, 2020

什么是TCP运输连接管理

TCP协议进行数据传输过程首先需要建立连接(即俗称的三次握手),之后才能进行数据传输,传输完成之后后需要关闭连接(即俗称的四次挥手)。 TCP运输连接管理就是指:使TCP的建立连接和关闭连接都能正常进行。

TCP的连接建立(三次握手)

TCP的连接建立流程图如上。

SYN:同步请求码,Synchronize Sequence Number。SYN=1的报文段不能携带请求数据。
seq:序列号。
ACK:确认码,Acknowledge character。

  1. TCP连接请求报文段:当client需要请求数据时client tcp主动打开,client向server发送tcp连接请求。此时server收到tcp建立连接请求时server端tcp连接从关闭状态处于监听状态。 此时client请求中SYN=1,seq=x。seq值由客户端生成。作为初始序列号。
  2. TCP连接请求确认报文段:接收到client建立tcp请求后server返回tcp连接建立请求确认消息。返回内容中包含tcp连接建立请求的SYN和seq,并返回确认码ACK和确认码序列号ack。此时server状态变更为同步已接收状态。
    • 确认位ACK=1表示消息确认。
    • 同步位SYN=1表示本次请求的同步请求码。
    • ack=x+1,在client发起的请求的序列号seq基础上+1表示对序列号为x的确认。
    • seq=y会重新由server生成一个序列号返回给client。作为server返回的初始序列号。
  3. TCP确认报文段:client接收到server返回的tcp连接建立确认报文段后再次向server发送一个tcp确认请求。此时:
    • ACK=1表示是一个普通的确认消息报文段。
    • ack=y+1,在server返回的tcp连接建立确认报文段的序列号基础上+1。表示对server初始序列号的确认。
    • seq=x+1,client序列号对比上一次client发起请求seq增加1。本次tcp请求可以携带请求数据,携带请求数据seq消耗+1。即若本次请求携带了数据那么下一次client向server发起的请求seq=x+2。若本次请求没有携带数据,那么下一次client向server发起的请求seq=x+1。

此时client进入连接已建立状态。server接收到client发送的tcp确认报文段后server也进入连接已建立状态。client与server可以开始基于建立好的tcp连接进行数据传输。

为什么需要三次握手,而不是两次就够了?最后一次client发起的tcp确认报文段是否多余?
不能省略最后tcp连接确认报文段的步骤。我们来看看一下的分析。

分析一:
client第一次发起的tcp连接请求由于网络抖动或其他原因失效,没有及时到达server。client发起第二个tcp连接请求。本次连接建立成功,client与server进行数据传输后释放了连接。client和server此时都处于关闭状态。但此时第一次的tcp请求到达了server端。server状态由关闭→监听,从而向client发起tcp连接确认报文段请求。由于只有二次握手client不会理会向server发送tcp确认,依然处于关闭状态。而server却会进入连接已建立状态,中间过程不会有任何数据传输,server端tcp连接会处于一直等待状态从而导致资源浪费。

分析二:
在tcp连接请求确认报文中,ack=x+1是对tcp连接请求client的初始化序列号的确认。seq=y是server生成的初始化序列号。若没有第三次tcp确认报文,那么server端的初始化序列号seq就得不到确认。导致无法对因为丢包或者是误码的tcp连接进行重试。

TCP连接释放(四次挥手)

TCP连接断开的过程如上图所示。

FIN:终止状态码
MSL:最长报文段寿命

client与server处于tcp连接建立通信状态,当client客户端应用主动关闭tcp连接时,client与server断开tcp连接将经历一下过程,一共分为四步,俗称为四次挥手。

  1. client向server发起tcp连接释放请求,client tcp由连接已建立状态进入终止等待状态。 请求报文中FIN和ACK均设置为1,表示该报文段为一个普通tcp连接释放请求报文。客户端生成初始序列号seq=u(为client进程上一次发送报文的最后一个序列号+1),确认码ack=v(为上一个client接收到的最后一个序列号+1)。

    tcp规定,FIN=1的报文段即使没有传输数据,序列号也会消耗,即下一次client发起的报文序列号seq=u+1。

  2. server接收到tcp连接释放报文段后向client发送tcp确认报文段,并进入关闭等待状态。同时会通知server端应用,client要断开连接。 ACK设置为1,表示这是一个普通的tcp确认报文段。seq设置为v为之前server最后一次传输报文的序列号+1,这也与第一步中client发起的tcp连接释放请求报文中的ack相匹配。ack设置为u+1表示对client序列号的确认。

    此时tcp连接处于半关闭状态,但server依然可以向client传输数据,client任然接收到server主动传输过来的数据。

  3. 持续一段时候后,server没有要向client发送的数据后,server进入最后确认状态并会向client发送tcp连接释放报文段。 报文段首部中FIN和ACK均设置为1,表示该报文段为一个普通tcp连接释放请求报文。seq设置为w(假设,在等待过程中可能server会有一些需要向client发送的数据)。ack设置为u+1,这是对client发送的tcp连接释放报文段序列号seq的确认。

  4. client接收到tcp连接释放报文段后进入时间等待状态,将等待2个MSL的时间,等待时长可以设定(有建议为2分钟)。并向server发送tcp确认报文段。server接收到client发送的tcp确认报文段则进入关闭状态。 tcp确认报文段中ACK设置为1,表示这是一个普通的tcp确认报文段。seq设置为u+1这是对client上一次发送报文段的序列号+1,ack设置为w+1表示对上一次接收到的server段报文序列号seq的确认。

以上client与server的tcp断开过程结束。client将在等待时间过后断开tcp。

为什么客户端需要等待2个MSL后才断开tcp,而不能接收到server的tcp连接释放报文段后就断开?
分析一下下面的场景

当client接收到server发送tcp连接释放报文段后,client向server发送tcp确认报文并进入关闭状态。若该tcp确认报文由于网络原因出现丢失,则server接收不到tcp确认报文返回会一直进行超时重试,server段tcp连接将一直处于最后确认状态无法关闭。

客户端等待为什么是2个MSL时间?
client发送最后一个确认报文段后,在2个MSL时间段内可以确保网络中所有的请求都消失。

TCP保活计时器

设想一下,当client与server建立完tcp连接后的某一时段client挂掉或者出现故障,那么server将一直处于等待消息接收状态。为了解决这个状态所以tcp连接中也需要保活计时器来避免这种情况的出现。 保活计时器的机制:

  • tcp服务进程每收到一次tcp客户端的数据后就重置保活计时器的时间(默认2小时)。
  • 若保活计时器周期时间内没有接收到client发来的数据请求,则当保活计时器到期后tcp server向client发送一个探测报文段,每75s发送一次,默认发送10次。若10次探测报文段后还没有接收到client进程的响应,则认为tcp client进程出现了故障可以关闭tcp server连接。