`
m635674608
  • 浏览: 5042791 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

TCP/IP协议--TIME_WAIT状态存在的原因

 
阅读更多

1. 实际问题
        初步查看发现,无法对外新建TCP连接时,线上服务器存在大量处于TIME_WAIT状态的TCP连接(最多的一次为单机10w+,其中引起报警的那个模块产生的TIME_WAIT约2w),导致其无法跟下游模块建立新TCP连接。
        TIME_WAIT涉及到TCP释放连接过程中的状态迁移,也涉及到具体的socket api对TCP状态的影响,下面开始逐步介绍这些概念。

2. TCP状态迁移
       面向连接的TCP协议要求每次peer间通信前建立一条TCP连接,该连接可抽象为一个4元组(four-tuple,有时也称socket pair):(local_ip, local_port, remote_ip,remote_port),这4个元素唯一地代表一条TCP连接。
       1)TCP Connection Establishment
       TCP建立连接的过程,通常又叫“三次握手”(three-way handshake),可用下图来示意:

       bubuko.com,布布扣

      可对上图做如下解释:
        a. client向server发送SYN并约定初始包序号(sequence number)为J;
        b. server发送自己的SYN并表明初始包序号为K,同时,针对client的SYNJ返回ACKJ+1(注:J+1表示server期望的来自该client的下一个包序为J+1);
        c. client收到来自server的SYN+ACK后,发送ACKK+1,至此,TCP建立成功。
        其实,在TCP建立时的3次握手过程中,还要通过SYN包商定各自的MSS,timestamp等参数,这涉及到协议的细节,本文旨在抛砖引玉,不再展开。

           2)TCPConnection Termination
       与建立连接的3次握手相对应,释放一条TCP连接时,需要经过四步交互(又称“四次挥手”),如下图所示:

        bubuko.com,布布扣
         可对上图做如下解释:
       a. 连接的某一方先调用close()发起主动关闭(active close),该api会促使TCP传输层向remotepeer发送FIN包,该包表明发起active close的application不再发送数据(特别注意:这里“不再发送数据”的承诺是从应用层角度来看的,在TCP传输层,还是要将该application对应的内核tcp send buffer中当前尚未发出的数据发到链路上)。                
       remote peer收到FIN后,需要完成被动关闭(passive close),具体分为两步:
       b. 首先,在TCP传输层,先针对对方的FIN包发出ACK包(主要ACK的包序是在对方FIN包序基础上加1);
       c. 接着,应用层的application收到对方的EOF(end-of-file,对方的FIN包作为EOF传给应用层的application)后,得知这条连接不会再有来自对方的数据,于是也调用close()关闭连接,该close会促使TCP传输层发送FIN。
       d. 发起主动关闭的peer收到remote peer的FIN后,发送ACK包,至此,TCP连接关闭。
       注意1:TCP连接的任一方均可以首先调用close()以发起主动关闭,上图以client主动发起关闭做说明,而不是说只能client发起主动关闭。
       注意2:上面给出的TCP建立/释放连接的过程描述中,未考虑由于各种原因引起的重传、拥塞控制等协议细节,感兴趣的同学可以查看各种TCP RFC Documents ,比如TCP RFC793

        3)TCP StateTransition Diagram
       上面介绍了TCP建立、释放连接的过程,此处对TCP状态机的迁移过程做总体说明。将TCP RFC793中描述的TCP状态机迁移图摘出如下(下图引用自这里):

     bubuko.com,布布扣
          TCP状态机共含11个状态,状态间在各种socket apis的驱动下进行迁移,虽然此图看起来错综复杂,但对于有一定TCP网络编程经验的同学来说,理解起来还是比较容易的。限于篇幅,本文不准备展开详述,想了解具体迁移过程的新手同学,建议阅读《Linux Network Programming Volume1》第2.6节。

3. TIME_WAIT状态
        
经过前面的铺垫,终于要讲到与本文主题相关的内容了。 ^_^
        从TCP状态迁移图可知,只有首先调用close()发起主动关闭的一方才会进入TIME_WAIT状态,而且是必须进入(图中左下角所示的3条状态迁移线最终均要进入该状态才能回到初始的CLOSED状态)。
        从图中还可看到,进入TIME_WAIT状态的TCP连接需要经过2MSL才能回到初始状态,其中,MSL是指Max
Segment Lifetime,即数据包在网络中的最大生存时间。每种TCP协议的实现方法均要指定一个合适的MSL值,如RFC1122给出的建议值为2分钟,又如Berkeley体系的TCP实现通常选择30秒作为MSL值。这意味着TIME_WAIT的典型持续时间为1-4分钟。
       TIME_WAIT状态存在的原因主要有两点:
    
   1)为实现TCP这种全双工(full-duplex)连接的可靠释放
       参考本文前面给出的TCP释放连接4次挥手示意图,假设发起active close的一方(图中为client)发送的ACK(4次交互的最后一个包)在网络中丢失,那么由于TCP的重传机制,执行passiveclose的一方(图中为server)需要重发其FIN,在该FIN到达client(client是active close发起方)之前,client必须维护这条连接的状态(尽管它已调用过close),具体而言,就是这条TCP连接对应的(local_ip, local_port)资源不能被立即释放或重新分配。直到romete peer重发的FIN达到,client也重发ACK后,该TCP连接才能恢复初始的CLOSED状态。如果activeclose方不进入TIME_WAIT以维护其连接状态,则当passive close方重发的FIN达到时,active close方的TCP传输层会以RST包响应对方,这会被对方认为有错误发生(而事实上,这是正常的关闭连接过程,并非异常)。
        2)为使旧的数据包在网络因过期而消失
       为说明这个问题,我们先假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port),因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。本文前面介绍过,TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的诡异现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。
       具体而言,local peer主动调用close后,此时的TCP连接进入TIME_WAIT状态,处于该状态下的TCP连接不能立即以同样的四元组建立新连接,即发起active close的那方占用的local port在TIME_WAIT期间不能再被重新分配。由于TIME_WAIT状态持续时间为2MSL,这样保证了旧TCP连接双工链路中的旧数据包均因过期(超过MSL)而消失,此后,就可以用相同的四元组建立一条新连接而不会发生前后两次连接数据错乱的情况。

另一比较深入的说法

TIME_WAIT状态的存在有两个理由:(1)让4次握手关闭流程更加可靠;4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保持一个2MSL的TIME_WAIT状态,则有更大的机会让丢失的ACK被再次发送出去。(2)防止lost duplicate对后续新建正常链接的传输造成破坏。lost duplicate在实际的网络中非常常见,经常是由于路由器产生故障,路径无法收敛,导致一个packet在路由器A,B,C之间做类似死循环的跳转。IP头部有个TTL,限制了一个包在网络中的最大跳数,因此这个包有两种命运,要么最后TTL变为0,在网络中消失;要么TTL在变为0之前路由器路径收敛,它凭借剩余的TTL跳数终于到达目的地。但非常可惜的是TCP通过超时重传机制在早些时候发送了一个跟它一模一样的包,并先于它达到了目的地,因此它的命运也就注定被TCP协议栈抛弃。另外一个概念叫做incarnation connection,指跟上次的socket pair一摸一样的新连接,叫做incarnation of previous connection。lost duplicate加上incarnation connection,则会对我们的传输造成致命的错误。大家都知道TCP是流式的,所有包到达的顺序是不一致的,依靠序列号由TCP协议栈做顺序的拼接;假设一个incarnation connection这时收到的seq=1000, 来了一个lost duplicate为seq=1000, len=1000, 则tcp认为这个lost duplicate合法,并存放入了receive buffer,导致传输出现错误。通过一个2MSL TIME_WAIT状态,确保所有的lost duplicate都会消失掉,避免对新连接造成错误。

 

Q: 编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思? 

 

A: 这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用 

端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息, 

指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧 

使用同一端口,此时 SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期 

望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不 

可能。

 

http://www.mamicode.com/info-detail-190400.html

http://www.cnblogs.com/li-hao/archive/2011/12/08/2280678.html

 

分享到:
评论

相关推荐

    TCP_IP算法.rar_C++算法_TCP/IP协议_TCP_IP_网络 协议 源码_网络协议

    源码分析可能涉及理解TCP的状态机,如CLOSED、LISTEN、SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、CLOSING、LAST_ACK、TIME_WAIT等状态及其转换。同时,还会涉及IP头部的解析,以及错误...

    TCP-TIMEOUT.rar_ tcp timeo_CFG TCP/IP TIMEOUT_TCP 超时_超时三次

    在TCP/IP协议栈中,TCP(传输控制协议)是一种面向连接的、可靠的传输协议,它通过复杂的机制确保数据能够正确无误地传输。本篇主要围绕“TCP超时”这一主题进行深入探讨,重点关注TCP的三次握手过程以及TCP/IP超时...

    【Linux网络编程笔记】TCP短连接产生大量TIME_WAIT导致无法对外建立新TCP连接的原因及解决方法—实践篇 - slv

    在TCP/IP通信中,TIME_WAIT状态是TCP连接生命周期的一部分,用于确保数据的可靠传输。当一个TCP连接被关闭后,连接的两端不会立即释放资源,而是进入TIME_WAIT状态,等待一段时间以确保所有发送的数据都被确认接收。...

    服务器大量TIME_WAIT解决方法

    在 TCP/IP 协议中,TIME_WAIT 状态是一种正常的连接状态。当一个 TCP 连接关闭时,服务器端会在 TIME_WAIT 状态下等待一段时间,以确保所有的数据包都已经被客户端收到。在这个状态下,服务器端会等待两个最大段生命...

    TIME_WAIT.rar_C-means_linux 网络状态_linux c wait_tcp_unix 网络编程

    在TCP/IP协议栈中,TIME_WAIT状态是为了确保数据的可靠传输而设计的。当一个TCP连接主动关闭后,发送端会进入TIME_WAIT状态,等待一段时间(通常称为2MSL,即最大段生存期的两倍)再释放连接。在此期间,任何迟到的...

    TCP/IP协议源码

    - **TCP连接管理**:包括三次握手建立连接、四次挥手断开连接的过程,以及TIME_WAIT和CLOSED状态的处理。 - **滑动窗口机制**:TCP通过滑动窗口控制发送速率,实现流量控制,防止接收方来不及处理过多的数据。 - **...

    TCP状态迁移,CLOSE_WAIT & FIN_WAIT2 的问题解决

    这是因为如果对方在第三次握手的时候出问题,例如发 FIN 包的时候,丢了这个包,然而这边一直处在 FIN_WAIT_2 状态,TCP/IP 并没有设置这个状态的过期时间,那它一直会保留这个状态下去,越来越多的 FIN_WAIT_2 状态...

    TCP/IP协议知识点总结与面试

    ### TCP/IP协议知识点总结与面试 #### 一、TCP/IP整体认知 TCP/IP协议栈是互联网的核心协议之一,由四个主要层次组成:应用层、传输层、网络层和链路层。TCP/IP协议栈不仅定义了如何封装和解封装数据,还定义了...

    net TCP/IP / TIME_WAIT / tcpip / iperf / cain

    标题中的“net TCP/IP / TIME_WAIT / tcpip / iperf / cain”涉及了多个IT领域的关键概念,包括网络协议、TCP/IP通信状态、性能测试工具和安全工具。接下来,我们将深入探讨这些知识点。 首先,TCP/IP是互联网的...

    解决mysql出现大量TIME_WAIT

    TIME_WAIT是TCP协议中的一个状态,当一个TCP连接正常关闭后,会进入TIME_WAIT状态,等待一段时间(通常是2MSL,即最大段生命周期的两倍)来确保网络中没有残留的数据包。在这个状态下,端口被占用,不能立即复用,这...

    关于释放time_wait连接多的方案

    在深入探讨如何有效释放TIME_WAIT状态的连接之前,我们首先需要理解TIME_WAIT状态的基本概念及其在TCP协议中的作用。TIME_WAIT是一种TCP连接的状态,当一个TCP连接被主动关闭时,客户端会进入TIME_WAIT状态,目的是...

    linux内核协议栈TCP time_wait原理、优化、副作用1

    Linux内核协议栈中的TCP协议在处理连接关闭时,会进入一个特定的状态叫做time_wait。这个状态对于确保TCP连接的可靠性和避免旧连接与新连接混淆至关重要。在time_wait状态下,连接不会立即关闭,而是等待一段时间,...

    netstat显示 TIME-WAIT 的原因及解决办法

    当我们看到netstat输出中存在大量的TCP连接处于TIME_WAIT状态时,这通常意味着系统可能存在一些性能问题或者配置上的挑战。本篇文章将深入探讨TIME_WAIT状态的原因以及如何解决。 TCP(传输控制协议)是一种面向...

    linux TCP/IP协议源码

    Linux TCP/IP协议源码是操作系统内核的一部分,用于实现网络通信的基本功能。它是一个复杂的、高度优化的软件组件,负责在网络层(IP)和传输层(TCP)处理数据的发送和接收。本主题将深入探讨Linux TCP/IP协议栈的...

    TCP/IP详解 卷3:TCP事务协议、HTTP、NNTP和UNIX域协议

    当客户与服务器进程在同一台主机上时,UNIX域协议通常要比TCP/IP快一倍。本书同样采用了大量的实例和实现细节,并参考引用了卷2中的大量源程序。适用于希望理解TCP/IP如何工作的人,包括编写网络应用程序的程序员...

    nginx+php产生大量TIME_WAIT连接解决办法1

    2. TCP/IP协议的设计,为了防止旧连接的延迟数据影响新连接,以及确保TCP连接可靠关闭,会将连接保持在TIME_WAIT状态一段时间,通常是两倍的MSL(最大段生存期)。 过多的TIME_WAIT连接虽然在正常情况下不会占用...

    TCP TIME_WAIT常见解决方法-hanwei_1049-ChinaUnix博客1

    TCP TIME_WAIT状态是TCP连接生命周期中的一个重要阶段,它发生在主动关闭连接的一方(通常称为客户端)在连接关闭后等待一段时间,以确保所有在网络中可能残留的数据片段都被接收并确认。这个阶段的存在是为了避免旧...

    减少Linux服务器过多的TIME_WAIT

    在Linux服务器环境中,当TCP/IP连接关闭后,服务器端的端口可能会进入TIME_WAIT状态,这是TCP协议设计的一部分。TIME_WAIT状态的目的是确保网络中不存在旧的、可能重复的数据包,从而避免对新连接造成干扰,并确保...

    TCP/IP详解(卷一)

    7. **TCP状态机**:详细展示了TCP连接在不同阶段的状态转换,包括CLOSED、LISTEN、SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、CLOSING、LAST_ACK和TIME_WAIT等状态。 8. **UDP的应用**...

    CLOSE_WAIT错误详解

    在TCP/IP协议栈中,CLOSE_WAIT是一个非常关键的连接状态,它涉及到客户端和服务器之间的通信。这个状态在处理网络连接时可能出现的问题时尤其重要。本文将深入探讨CLOSE_WAIT错误的含义、原因以及如何解决。 首先,...

Global site tag (gtag.js) - Google Analytics