TCP 连接关闭的 TIME_WAIT (2MSL) 状态,及 TCP 连接状态图

上学时画的 TCP 连接状态图,本来是为了搞清楚 socket 编程时的一个问题:客户端通常不绑定(bind()) inet 地址结构,而采用随机的端口建立连接 socket(connect())。如果客户端绑定一个指定端口的 inet 地址,一般在运行完第一次客户端后,紧接着第二次运行客户端,就会出现客户端 socket 无法绑定先前的 inet 地址了,程序也就无法继续运行,大概过上几分钟后再运行客户端,绑定过程又恢复正常了。当时我知道一般客户端是不 bind() 地址的,因为这样就无法在一台主机上同时起多个客户端了,可是和时间相关的 bind() 问题的原因是什么,当时很晕乎。

闲话 socket

话说一个活动的 socket 实例是一个 7 元组(仅限 UDP/TCP,其它传输协议未接触):<地址家族, socket 类型, 传输协议类型>(这 3 者确定一个 socket 种类),加上 <本地 IP, 本地端口, 远端 IP, 远端端口> 这 4 元组,这 7 元组标识一台主机上的唯一一个活动 socket,也就是说不可能在一台主机上有两个以上的这 7 元组都相同的 socket,换句话说只要这 7 个中有一个分量不同,就可以成为两个 socket。

监听 socket(listen()),通常绑定在 INADDR_ANY(32 位整数 0)的 IP 上(多穴主机的监听就酱子),则后 4 元组为:<0.0.0.0, local-port, 0.0.0.0, remote-port>(netstat 或 tcpview 等工具很方便查看这些信息)。接受 socket 也即服务端的连接 socket,是 accept() 从 监听 socket 复制出来的,其关联的地址 4 元组为:<spec-local-ip, local-port, remote-ip, remote-port>,其中 spec-local-ip 是实际的接收包的 NIC 的 IP 地址,而不是 0.0.0.0 了。

 

最后仔细看了书,结合 netstat 等工具,并翻了 RFC 793 (Transmission Control Protocol),最后明白了这个问题的原因:通常是客户端发起连接断开的操作(close() 或 winsock 的 closesock()),一系列 FIN 连接断开握手后,服务端的连接 socket 的生命就结束了(CLOSED 状态,资源释放),但是客户端的连接 socket 会停留在 TIME_WAIT 状态(虽然它对应的 TCP 连接确实已经断开了),持续 2 倍的 MSL(Maximum Segment Lifetime)时间,大约 2 分钟左右。

其实,谁发起断开请求(FIN)谁倒霉,如果是服务器主动断开,则它也需要等待 2MSL 时间,等待上回的 socket 到达 CLOSED 状态资源释放,叫做服务器平静时间。看看下面的 TCP 连接断开说明:

TCP Connection Termination

from: www.tcpipguide.com

The device receiving the initial FIN may have to wait a fairly long time (in networking terms) in the CLOSE-WAIT state for the application it is serving to indicate that it is ready to shut down. TCP cannot make any assumptions about how long this will take. During this period of time, the server in our example above may continue sending data, and the client will receive it. However, the client will not send data to the server.

Eventually, the second device (the server in our example) will send a FIN to close its end of the connection. The device that originally initiated the close (the client above) will send an ACK for this FIN. However, the client cannot immediately go to the CLOSED state right after sending that ACK. The reason is that it must allow time for the ACK to travel to the server. Normally this will be quick, but delays might result in it being slowed down somewhat.

The TIME-WAIT state is required for two main reasons. The first is to provide enough time to ensure that the ACK is received by the other device, and to retransmit it if it is lost. The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could be mixed, creating confusion.

The standard specifies that the client should wait double a particular length of time called the maximum segment lifetime (MSL) before finishing the close of the connection. The TCP standard defines MSL as being a value of 120 seconds (2 minutes). In modern networks this is an eternity, so TCP allows implementations to choose a lower value if it is believed that will lead to better operation.

于是我画了 TCP 连接状态图,不过只有下半部连接断开的操作,如下:

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 RFC 793 中的 TCP 连接状态图

RFC 793 中也有这个状态图(第 23 页,图 6),从发起连接到连接断开,很详细(RFC 的 ASCII 画图,我膜拜):

                              +---------+ ---------/      active OPEN
                              |  CLOSED |            /    -----------
                              +---------+<---------/   /   create TCB
                                |     ^              /   /  snd SYN
                   passive OPEN |     |   CLOSE        /   /
                   ------------ |     | ----------       /   /
                    create TCB  |     | delete TCB         /   /
                                V     |                      /   /
                              +---------+            CLOSE    |    /
                              |  LISTEN |          ---------- |     |
                              +---------+          delete TCB |     |
                   rcv SYN      |     |     SEND              |     |
                  -----------   |     |    -------            |     V
 +---------+      snd SYN,ACK  /       /   snd SYN          +---------+
 |         |<-----------------           ------------------>|         |
 |   SYN   |                    rcv SYN                     |   SYN   |
 |   RCVD  |<-----------------------------------------------|   SENT  |
 |         |                    snd ACK                     |         |
 |         |------------------           -------------------|         |
 +---------+   rcv ACK of SYN  /       /  rcv SYN,ACK       +---------+
   |           --------------   |     |   -----------
   |                  x         |     |     snd ACK
   |                            V     V
   |  CLOSE                   +---------+
   | -------                  |  ESTAB  |
   | snd FIN                  +---------+
   |                   CLOSE    |     |    rcv FIN
   V                  -------   |     |    -------
 +---------+          snd FIN  /       /   snd ACK          +---------+
 |  FIN    |<-----------------           ------------------>|  CLOSE  |
 | WAIT-1  |------------------                              |   WAIT  |
 +---------+          rcv FIN  /                            +---------+
   | rcv ACK of FIN   -------   |                            CLOSE  |
   | --------------   snd ACK   |                           ------- |
   V        x                   V                           snd FIN V
 +---------+                  +---------+                   +---------+
 |FINWAIT-2|                  | CLOSING |                   | LAST-ACK|
 +---------+                  +---------+                   +---------+
   |                rcv ACK of FIN |                 rcv ACK of FIN |
   |  rcv FIN       -------------- |    Timeout=2MSL -------------- |
   |  -------              x       V    ------------        x       V
    / snd ACK                 +---------+delete TCB         +---------+
     ------------------------>|TIME WAIT|------------------>| CLOSED  |
                              +---------+                   +---------+

                      TCP Connection State Diagram
                               Figure 6.
Oknet 的 TCP 状态图

在 Oknet 的 Blog:关于服务器端程序编写与TCP状态 CLOSE_WAIT,TIME_WAIT,中找到一张图,也挺全,比 RFC 的看起来舒服些:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

end。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值