TCP连接管理

TCP 连接建立和释放

Posted by Sun Jianjiao on August 20, 2011

1. TCP 报文段首部格式

TCP虽然时面向字节流的,单TCP传送的的数据单元却是报文段。分为首部和数据两部分。

TCP报文首部

只介绍后面用的字段的含义:

  • 序号(seq): 占4字节。如果增加到 $2 ^ 32$ - 1, 下一个序号就会又回到0.在一个TCP连接中传送的字节流中的每一个字节都按照顺序编号。首部中的序号字段指的是本报文所发送的数据的第一个字节的序号。
  • 确认号(ack): 占4个字节,是期望对方下一个报文段的第一个数据字节的序号。若确认号 = N,则表明:到序号N - 1 为止的所有数据到一确认收到。
  • 确认ACK(ACKnowledgement): ACK = 1是,确认号字段才有效。ACK=0时,确认号无效。TCP规定,在连接建立后,所有传送的报文段都必须把ACK设置为1.
  • 同步SYN(SYNChronization): 连接建立时用来同步序号。当SYN = 1而ACK = 0时,表示这是一个连接请求报文段。若对方同意建立连接,则应在响应报文段中使用SYN = 1 和 ACK = 1。因此SYN = 1表示这是一个连接请求连接接受报文。
  • 中止FIN(FINis, 意思是“完”、“终”):用来释放一个链接。当FIN = 1,表明此报文段的发送方的数据已经发送完毕,并要求释放运输连接

2. 连接建立

三报文握手

2.1 同步已发送

客户端向服务端发送连接请求报文,客户端进入同步已发送状态(SYN_SEND)。 同步位SYN = 1的的报文段不能携带数据,但要消耗掉一个序号。

2.2 同步已收到

B收到连接请求报文后,如果同意建立连接,则向客户端发送接收请求报文,服务端服务器进入同步已收到状态(SYN_RCVD)

2.3 连接已建立

客户进程收到B的确认后,还要向服务端给出确认报文

  • 这时TCP连接已经建立,客户端进入连接已建立状态(ESTABLISHED),
  • 服务端收到客户端的确认后,服务端也进入连接已建立状态(ESTABLISHED)

客户端进入连接已建立状态(ESTABLISHED),服务端进入连接已建立状态(ESTABLISHED)

2.4 为什么最后还要发送一次确认呢

主要是为了防止已失效的连接请求报文突然又传到B而产生错误。

  • 如果客户端发出请求,没有收到确认。客户端以为消息丢失,于是客户端重传请求,收到确认,建立了连接。
  • 数据传输完毕后,释放了连接。
  • 但是第一次的请求报文没有丢失,只是滞留了,导致延误到达了。
  • 服务器收到此失效的报文后,误认为客户端又发出一次新的连接请求。于是就向A发出确认报文,同意建立连接。

假如没有最后的确认报文,服务端发出报文,新的连接就建立了。客户端并没有发起请求,不会向B发送数据,但是服务端会一直等待A,造成服务端的资源浪费

3 连接释放

三报文握手

数据传输结束后,通信的双方都可以释放报文段,并停止发送数据,主动关闭TCP连接。

3.1 中止等待1 (FIN_WAIT-1)

A设置FIN = 1, seq = u(前面一传送过的数据的最后一个字节的序号加1)。这是A进入中止等待 1 (FIN_WAIT-1)状态。等待 B 确认。

3.2 半关闭状态

B收到释放报文段后发出确认,确认好事ack = u + 1, 这个报文自己的序号是 seq = v(前面一传送过的数据的最后一个字节的序号加1)。B进入关闭状态(CLOSE-WAIT), A 到B方向的连接就释放了, 这时TCP连接处于半关闭(half-close)状态, 即A已经没有数据要发送了,若B发送数据,A仍要接收。这个过程可能要持续一段时间。

A 收到B的确认后,进入FIN-WAIT-2状态。等待B发出连接释放的报文。

3.3 最后确认状态

若B已经没有要向A发送的数据,其应用就通知TCP释放连接。这是B发出的报文需要设置FIN = 1。并且设置ack = u + 1。这时候B进入了LAST-ACK最后确认状态。

3.4 关闭状态

A 收到 B的连接释放报文后,必须对此报文进行确认。设置ACK = 1, ack = 2 + 1, 进入到TIME-WAIT(时间等待)状态。TCP 还没有释放掉, 必须经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL(RFC793建议MSL = 2分钟)后才能释放。也就是要经过4分钟才能进入到CLOSED状态,才能开始建立下一个新的连接。

为什么要等待2MSL的时间呢?

  • 保证A发送的最后一个ACK报文能够到达B。这个ACK报文可能丢失,使得处在LAST-ACK的B收不到确认报文,B会超时进行重传,A能在2MSL时间内收到重传的FIN+ACK报文,A重新确认,并且重新启动2MSL计时器。保证最终A和B都能正常进入到CLOSED状态。
  • 防止已失效的请求连接报文段出现在本链接中。A发送完最后一个ACK报文后,在经过时间2MSL,就可以是本地连接持续时间内所产生的所有报文段都从网络消失。

除了等待时间计数器外,TCP还有一个保活计时器。 如果客户端已经建立来连接,但是主机突然故障。服务器就不能再收到客户发来的数据,服务器不能白白等待下去。服务器没收到一次客户的数据,就重新设置保活计数器。时间通常是2小时。若2个小时未收到客户的数据,服务器就发送一个探测报文段,以后每个75秒发送一次。若连续发送10个探测报文段后仍无客户响应,服务七九认为客户端除了故障,接着就关闭这个链接。