TCP连接和 time_wait、close_waite

tags:time_wait close_waite RST TCP


引言:前两天朋友公司的服务器垮掉了,最后查出的原因是发现大量的time_wait网络状态。被问起来time_wait是什么,当时就简单的给解释了两句,后来想想正好博客没有特别好的话题,拿来写一下也很不错。

简单的描述产生原因

因为本文较长,如果没有耐心的可以简单了解一下,有耐心的请阅读全文。

TCP是面向连接的,即使不知道具体的过程,也都知道TCP的三次握手,四次挥手。挥手也就是关闭连接,关闭连接的时候,主动关闭的一方在接收到被动关闭方的回应前,处于time_wait状态,并保持一段时间。close_wait是被动关闭方接收到关闭链接请求后所处的状态。

查看状态的代码:

$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

>结果
$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
CLOSE_WAIT 134
ESTABLISHED 245 //已经建立连接,正在传输状态
TIME_WAIT 3

TCP的三次握手和四次挥手的状态转换

要说清楚这个状态,需要了解一定的TCP知识,我们在这里简单介绍一下

三次握手建立连接

TCP必须经过三次握手来建立可靠连接才能彼此传输数数据。假设请求方为客户端与服务端建立TCP连接

在握手前,TCP服务器进程已经创建传输控制块TCB(传输控制模块,记录TCP

运行过程中的变量),准备接受客户连接请求,此时服务器进入LISTEN(监听)状态;

第一次握手:TCP客户端先创建传输控制块TCB,然后向服务器发出连接请求报文,这时报文首部中的同步位SYN=1,初始序列号 seq=x ,TCP客户端进程进入了SYN_SENT(同步已发送)状态。TCP协议中SYN报文段(SYN=1的报文段)不携带数据,但需要消耗掉一个序号(序号每次报文要递增)。

第二次握手:服务端在收到客户端发过来的SYN请求报文后,如果同意连接,则发出确认报文。确认报文ACK=1,SYN=1,确认号是ack=x+1(这个ack是确认号,大写的ACK是标志位,文章最末尾有各个标志位的简单介绍),同时自己也初始化一个序列号 seq=y,此时,服务器TCP进程进入了SYN_RCVD(收到同步)状态。这个SYN同样不携带数据,且消耗一个序号。

第三次握手:客户端口收到服务端发过来的SYN和ACK确认报文后,还要向服务器给出确认,确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,客户端状态由原来的SYN_SENT状态变为ESTABLISHED(连接已确认建立)。TCP协议中ACK报文可以携带数据,携带数据的时候消耗序号

服务端收到报文后,由原来的SYN_RCVD变为ESTABLISHED,双方开始通信

三次握手有一个很形象的比喻

//客户端和服务端打电话
客户端:服务端你能听见吗
服务端:哎,能听见,你能听见我说话吗
客户端:能听见,有点事找你(如果没有这一步,服务端并不知道客户端是否能听见)

四次挥手关闭连接

先来解释一个TCP连接到底是谁关闭的,一般来说,谁断开都可以,对于我们常用的http来说,一般情况下是这样的

  • 对于http1.0协议

    1. 如果响应头中有content-length头,则以content-length的长度就可以知道body的长度了,客户端在接收body时,就可以依照这个长度来接收数据,接收完后,就表示这个请求完成了,客户端请求断开。
    2. 如果没有content-length头,则客户端会一直接收数据,直到服务端主动断开连接,才表示body接收完了。
  • 对于http1.1协议

    1. 如果响应头中的Transfer-encoding为chunked传输,则表示body是流式输出,body会被分成多个块,每块的开始会标识出当前块的长度,此时,body不需要通过长度来指定,客户端主动请求断开。
    2. 如果是非chunked传输,而且有content-length,则按照content-length来接收数据,接收完成后客户端请求断开连接。
    3. 如果是非chunked,并且没有content-length,则客户端接收数据,直到服务端主动断开连接。

下面说四次挥手的过程

我们假设客户端是请求关闭连接的一方,服务端为被动关闭

第一次挥手:客户端进程发请求关闭(或称释放)连接报文,并且停止发送数据。数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN_WAIT_1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

第二次挥手:服务器收到请求关闭报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE_WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE_WAIT状态持续的时间。

客户端收到服务器的确认请求后,此时,客户端就进入FIN_WAIT_2(终止等待2)状态,等待服务器发送关闭连接报文(在这之前还需要接受服务器发送的最后的数据)。

第三次挥手:服务器将最后的数据发送完毕后(或者没有需要发送的数据),就向客户端发送关闭连接报文,FIN=1,ack=u+1。由于服务器很可能又发送了一些数据,所以假定此时的序列号为seq=w,此时,服务器就进入了LAST_ACK(最后确认)状态,等待客户端的确认。

第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME_WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最大报文段寿命)的时间,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。撤销TCB后,就结束了这次的TCP连接。可以看到,服务器(被动断开方)结束TCP连接的时间要比客户端(主动断开方)早一些。

//客户端和服务端打电话
客户端:我的事说完了,有事情你说我听着,没什么事挂了哈
服务端:好的知道了,(好的,我还要和你说个事,你妈叫你回家吃饭)
服务端:行了挂了吧
客户端:哦,知道了,那我挂了

关于为什么要等待2MSL:

MSL(Maximum Segment Lifetime),这是TCP 对TCP Segment 生存时间的限制。

客户端发送最后一个ACK后,不能确保服务端一定能收到,假如ACK没有被服务端收到,超时后服务端重新进行第三次挥手,这时候如果A还在等待,又收到第三次挥手的FIN消息,证明ACK没有成功到达,这个时间至少是:服务端的超时时间 + FIN的传输时间,为了保证可靠,采用更加保守的等待时间2MSL。

如果客户端此时没有在等待状态直接CLOSED,服务端超时后发送FIN消息到客户端,客户端表示并不知道这数据包是干什么的,所以响应一个RST(用来异常的关闭连接,请自行了解),如果客户端有一个和服务端的新连接在这个端口上建立。这将可能导致后面建立的连接受到影响,TCP是可靠的连接,所以是不希望这种不靠谱的事情出现的。这种错误可以比喻为

//客户端和服务端打电话
客户端:我的事说完了,有事情你说我听着,没什么事挂了哈
服务端:好的知道了,(好的,我还要和你说个事,你妈叫你回家吃饭)
服务端:行了挂了吧
客户端:哦,知道了,那我挂了
(上面这一句因为信号不好等原因服务端没收到客户端就挂了电话)后面有事情又拨通了服务端电话(建立了新连接)
服务端:挂了吧
客户端:怎么回事,蛇精病啊,刚通了就让我挂

TCP报文首部标志位

关于报文首部格式,网上有很多,而且大部分都是以正确的,下面只介绍和本文有关的,

  • 标志位:

    1. SYN(synchronous建立联机)

      在连接建立时用来同步序号,当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意时,则应在响应的报文段中使SYN=1和ACK=1,因此,SYN置1就表示这是一个连接请求或连接接受报文。
    2. ACK(acknowledgement 确认)

      仅当ACK=1时确认号字段才有效,TCP规定,连接建立后所有传送的报文段都必须把ACK置1.
    3. PSH(push传送)

      当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送操作。
    4. FIN(finish结束)

      用来释放一个连接,当FIN=1时,表示此报文段的发送方的数据已发送完毕,并要求释放运输连接。
    5. RST(reset重置)

      当RST=1时,表明TCP连接中出现严重错误,必须释放连接,然后再重新建立运输连接。
    6. URG(urgent紧急)

      当URG=1时,表明紧急字段有效,告诉系统此报文中有紧急数据,应尽快传送。
  • 其他:

    1. Sequence number(顺序号码)

      seq是发送的数据包本身的序列号;
    2. Acknowledge number(确认号码)

      ack是对收到的数据包的确认,值是等待接收的数据包的序列号。即期望对方继续发送的那个数据包的序列号。

TCP连接和 time_wait、close_waite的更多相关文章

  1. TCP连接的TIME_WAIT和CLOSE_WAIT 状态解说【转】

    相信很多运维工程师遇到过这样一个情形: 用户反馈网站访问巨慢, 网络延迟等问题, 然后就迫切地登录服务器,终端输入命令"netstat -anp | grep TIME_WAIT | wc ...

  2. 经典!服务端 TCP 连接的 TIME_WAIT 过多问题的分析与解决

    开源Linux 专注分享开源技术知识 本文给出一个 TIME_WAIT 状态的 TCP 连接过多的问题的解决思路,非常典型,大家可以好好看看,以后遇到这个问题就不会束手无策了. 问题描述 模拟高并发的 ...

  3. TCP连接(Time_Wait、Close_Wait)说明

    修改Time_Wait和CLOSE_WAIT时间 修改Time_Wait参数的方法 (在服务端修改)Windows下在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlS ...

  4. TCP连接中time_wait在开发中的影响-搜人以鱼不如授之以渔

    根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),T ...

  5. TCP/IP详解--TCP连接中TIME_WAIT状态过多

    TIMEWAIT状态本身和应用层的客户端或者服务器是没有关系的.仅仅是主动关闭的一方,在使用FIN|ACK|FIN|ACK四分组正常关闭TCP连接的时候会出现这个TIMEWAIT.服务器在处理客户端请 ...

  6. TCP连接的TIME_WAIT和CLOSE_WAIT 状态解说

    相信很多运维工程师遇到过这样一个情形: 用户反馈网站访问巨慢, 网络延迟等问题, 然后就迫切地登录服务器,终端输入命令"netstat -anp | grep TIME_WAIT | wc ...

  7. mysql服务器,大量tcp连接状态TIME_WAIT

    今天早上,java应用中发现too many open files,检查了下使用的连接数发现基本上在两三百左右,mysql打开的文件数也就几百左右,再看所有tcp连接,发现3306的连接有4000多, ...

  8. 服务器TCP连接中 TIME_WAIT 状态过多

    今天查看服务器的TCP连接数,发现其中 TIME_WAIT 状态的太多了: # netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a ...

  9. TCP 连接的 TIME_WAIT 过多 导致 Tomcat 假死

    最近系统二次开发之后,发现使用的 Tomcat 7 会经常假死.前端点击页面无任何反应,打开firebug,很多链接一直在等待服务器的反应.查看服务器的状态,CPU占用很少,最多不超过10%,一般只有 ...

随机推荐

  1. 安卓TV开发(五) 移动智能终端UI之实现主流TV焦点可控UI

      载请标明出处:http://blog.csdn.net/sk719887916,作者:skay    由于其他网站收录,导致你无法查看本系列原创文章请点击此处 安卓TV开发(四)实现主流智能T ...

  2. 3、使用Gradle创建Libgdx项目

    (原文链接:http://www.libgdx.cn/topic/20/3-%E4%BD%BF%E7%94%A8gradle%E5%88%9B%E5%BB%BAlibgdx%E9%A1%B9%E7%9 ...

  3. mpi中程序在集群中的分发

    我们在开发mpi程序时,由于其是分布式程序,我们在单个节点上完成编码后,需要将代码拷贝到整个集群进行测试.集群之间的文件拷贝可以通过scp命令完成.但是scp命令是针对两个节点之间文件互传设计,为了将 ...

  4. (NO.00001)iOS游戏SpeedBoy Lite成形记(二)

    打开SpriteBuilder生成的Xcode项目文件,首先在MainScene添加play回调函数: -(void)play{ CCScene *gameScene = [CCBReader loa ...

  5. 03_Nginx添加新模块

     1 进入nginx安装目录,查看nginx版本及其编译参数: [root@localhost nginx]# ./nginx -V nginx version: nginx/1.8.0 buil ...

  6. kettel的stream lookup报错

    kettel的stream lookup报错: you can't use the 'integer-pair' algorithm when you have more than one key o ...

  7. Aprior算法

    在关联规则挖掘领域最经典的算法法是Apriori,其致命的缺点是需要多次扫描事务数据库.于是人们提出了各种裁剪(prune)数据集的方法以减少I/O开支,韩嘉炜老师的FP-Tree算法就是其中非常高效 ...

  8. Android群英传笔记——第二章:Android开发工具新接触

    Android群英传笔记--第二章:Android开发工具新接触 其实这一章并没什么可讲的,前面的安装Android studio的我们可以直接跳过,如果有兴趣的,可以去看看Google主推-Andr ...

  9. PS 图像调整算法— —渐变映射

    这个调整简单来说就是先建立一张lookup table, 然后以图像的灰度值作为索引,映射得到相应的颜色值.图像的灰度值是由图像本身决定的,但是lookup table 却可以各种各样,所以不同的lo ...

  10. 熊猫猪新系统测试之三:iOS 8.0.2

    本来本猫要等到8.1版本出来后再做测试的,结果等来等去就是迟迟不推送更新呀!说好10月20号的iOS 8.1呢?为了一鼓作气写完,就先不等了.先拿手头的iOS 8.0.2系统做一下测试吧! 8.x系统 ...