TIME_WAIT状态分析

先仍给出一段测试代码,同CLOSE_WAIT状态分析一文测试代码,main函数如下.测试后,会发现两边有大量的TIME_WAIT连接.

int main(int argc, char* argv[]){
    int sender = 0;
    int ret    = 0;
    int listen_sock = 0;
    if(argc !=2){
         printf("usage: ./test 1/n");
         return -1;
    }
    sender = atoi(argv[1]);
    if(sender){
       while(1){
           ret = socket_connect("10.224.55.145",8765);
           if(ret < 0){
               return -1;
           }else{
               close(ret);
           }
        }
    }else{
        listen_sock = socket_listen(8765,100);
        if(listen_sock < 0){
           return -1;
       }else{
            while(1){
               ret = socket_accept(listen_sock,NULL);
               if(ret < 0){
                  return -1;
               }else{
                  close(ret);
             }
         }
        }
    }
    return 0;
}


CLOSE_WAIT状态分析一文已经介绍了一个通常的TCP连接终止的过程.我们以CLIENT端断开连接重新介绍下:

CLIENT---   FIN  --- SERVER

SERVER---  ACK  --- CLIENT

SERVER---   FIN  --- CLIENT

CLIENT---   ACK --- SERVER

步骤III,SERVER发送FIN报文后进入LAST_ACK状态.步骤IV,CLIENT接收到FIN报文并发出ACK报文后进入TIME_WAIT状态.(当SERVER收到ACK报文后,也即可以进入到CLOSED可用状态了).

 

下面先解释一下TIME_WAIT状态存在的原因.
MSL(最大分段生存期)指明TCP报文在Internet上最长生存时间,每个具体的TCP实现都必须选择一个确定的MSL值.TIME_WAIT 状态最大保持时间是2*MSL.

TCP报文在传送过程中可能因为路由故障被迫缓冲延迟,选择非最优路径等等,结果发送方TCP机制开始超时重传.前一个TCP报文可以称为"漫游TCP重复报文",后一个TCP报文可以称为"超时重传TCP重复报文".假设最终的ACK并未被SERVER端收到,则SERVER端将重发FIN,client必须维护TCP状态信息以便可以重发最终的ACK,否则会发送RST,然后server认为发生错误.TCP实现必须可靠地终止连接的两个方向(全双工关闭),client必须进入TIME_WAIT 状态,因为client可能面临重发最终ACK的情形.

 

如果 TIME_WAIT 状态保持时间不足够长(比如小于2MSL),第一个连接就正常终止了, 第二个拥有相同相关五元组的连接出现,而第一个连接的重复报文到达,干扰了第二 个连接.TCP实现必须防止某个连接的重复报文在连接终止后出现,所以让TIME_WAIT 状态保持时间足够长(2MSL),连接相应方向上的TCP报文要么完全响应完毕,要么被 丢弃.建立第二个连接的时候,不会混淆.


先调用close()的一方会进入TIME_WAIT状态.

 

我们写server程序总是在调用bind()之前设置SO_REUSEADDR套接字选项.这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT,可以重用端口.如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息.如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时 SO_REUSEADDR 选项非常有用.必须意识到,会出现上面说的问题,当接收到的连接相关五元组的(协议,本地地址,本地端口,远程地址,远程端口)相同时,程序有可能收到非期望数据.

 

不过一般的端口分配算法能保证五元组中的远程端口是不一样的.客户端的端口分配一般是自动的,且一般都是从上一次分配的端口号+1开始分配的.所以我们要知道的就是理论上有这种可能,事实上是很不可能.

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章