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. SpriteBuilder中音频文件格式的需要注意的地方

    就像在SpriteBuilder项目子目录中的其他资源文件一样,音频文件夹需要确定完整的文件夹路径. 并且如果音频文件输出格式为MP4,则扩展为.m4a(audio-only MPEG4)而不是.mp ...

  2. 我也来写DBUtils

    关于重复造轮子 作为一个程序员,我们不止一次听到师长前辈们说:不要重复造轮子,已经有现成的了,直接用就是了. 对于这个观点,我觉得得仔细分析分析. 如果我们正在做一个真实的项目,经理天天追在我们屁股后 ...

  3. LeetCode之“树”:Validate Binary Search Tree

    题目链接 题目要求: Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is ...

  4. Java的依赖注入(控制反转)

    两个主角"依赖注入"和"控制反转": 1.二都说的都是同一件事,只是叫法不同.是一个重要的面向对象编程的法则,也是一种设计模式: 2.英文原称:依赖注入,Dep ...

  5. iOS监听模式系列之iOS开发证书、秘钥

    补充--iOS开发证书.秘钥 iOS开发过程中如果需要进行真机调试.发布需要注册申请很多证书,对于初学者往往迷惑不解,再加上今天的文章中会牵扯到一些特殊配置,这里就简单的对iOS开发的常用证书和秘钥等 ...

  6. C语言之归并排序

    即将两个都升序(或降序)排列的数据序列合并成一个仍按原序排列的序列. 上代码: #include <stdio.h> #include <stdlib.h> #define m ...

  7. 【Matlab编程】马氏链随机模拟

    本文是利用蒙特卡罗算法对马氏链过程的模拟.假设有10个状态,从每个状态到与之相邻状态的概率是相同的,仿真次数为1000,及进行了1000次状态转移.我们以动画的形式再现了状态转移的过程,并记录了到达每 ...

  8. RGB颜色转换算法C语言实现

    typedef unsigned short     TUINT16; #define RGB565(R, G, B) \ (((TUINT16) ((R) >> 3)) << ...

  9. 面试心得随谈&线程并发的总结

    ---恢复内容开始--- 线程同步有两种实现方式: 基于用户模式实现和用内核对象实现.前者偏于轻量级,性能也更好,但是只能用于同一进程间的线程同步,后者重量级,性能消耗更大,跨进程. 研读了一下win ...

  10. 八、Join 连接查询

    文档目录 开发中...