下图所示,TCP通信过程包括三个步骤:建立TCP连接通道(三次握手)、数据传输、断开TCP连接通道(四次挥手)。

这里进一步探究TCP三路握手和四次挥手过程中的状态变迁以及数据传输过程。先看TCP状态状态转换图。

上半部分是TCP三路握手过程的状态变迁,下半部分是TCP四次挥手过程的状态变迁。

  • CLOSED:起始点,在超时或者连接关闭时候进入此状态,这并不是一个真正的状态,而是这个状态图的假想起点和终点。
  • LISTEN:服务器端等待连接的状态。服务器经过 socket,bind,listen 函数之后进入此状态,开始监听客户端发过来的连接请求。此称为应用程序被动打开(等到客户端连接请求)。
  • SYN_SENT:第一次握手发生阶段,客户端发起连接。客户端调用 connect,发送 SYN 给服务器端,然后进入 SYN_SENT 状态,等待服务器端确认(三次握手中的第二个报文)。如果服务器端不能连接,则直接进入CLOSED状态。
  • SYN_RCVD:第二次握手发生阶段,跟 3 对应,这里是服务器端接收到了客户端的 SYN,此时服务器由 LISTEN 进入 SYN_RCVD状态,同时服务器端回应一个 ACK,然后再发送一个 SYN 即 SYN+ACK 给客户端。状态图中还描绘了这样一种情况,当客户端在发送 SYN 的同时也收到服务器端的 SYN请求,即两个同时发起连接请求,那么客户端就会从 SYN_SENT 转换到 SYN_REVD 状态。
  • ESTABLISHED:第三次握手发生阶段,客户端接收到服务器端的 ACK 包(ACK,SYN)之后,也会发送一个 ACK 确认包,客户端进入 ESTABLISHED 状态,表明客户端这边已经准备好,但TCP 需要两端都准备好才可以进行数据传输。服务器端收到客户端的 ACK 之后会从 SYN_RCVD 状态转移到 ESTABLISHED 状态,表明服务器端也准备好进行数据传输了。这样客户端和服务器端都是 ESTABLISHED 状态,就可以进行后面的数据传输了。所以 ESTABLISHED 也可以说是一个数据传送状态。
  • 上面就是 TCP 三次握手过程的状态变迁。结合第一张三次握手过程图,从报文的角度看状态变迁:SYN_SENT 状态表示已经客户端已经发送了 SYN 报文,SYN_RCVD 状态表示服务器端已经接收到了 SYN 报文。

下面看看TCP四次挥手过程的状态变迁。结合第一张四次挥手过程图来理解。

  • FIN_WAIT_1:第一次挥手。主动关闭的一方(执行主动关闭的一方既可以是客户端,也可以是服务器端,这里以客户端执行主动关闭为例),终止连接时,发送 FIN 给对方,然后等待对方返回 ACK 。调用 close() 第一次挥手就进入此状态。
  • CLOSE_WAIT:接收到FIN 之后,被动关闭的一方进入此状态。具体动作是接收到 FIN,同时发送 ACK。之所以叫 CLOSE_WAIT 可以理解为被动关闭的一方此时正在等待上层应用程序发出关闭连接指令。前面已经说过,TCP关闭是全双工过程,这里客户端执行了主动关闭,被动方服务器端接收到FIN 后也需要调用 close 关闭,这个 CLOSE_WAIT 就是处于这个状态,等待发送 FIN,发送了FIN 则进入 LAST_ACK 状态。
  • FIN_WAIT_2:主动端(这里是客户端)先执行主动关闭发送FIN,然后接收到被动方返回的 ACK 后进入此状态。
  • LAST_ACK:被动方(服务器端)发起关闭请求,由状态2 进入此状态,具体动作是发送 FIN给对方,同时在接收到ACK 时进入CLOSED状态。
  • CLOSING:两边同时发起关闭请求时(即主动方发送FIN,等待被动方返回ACK,同时被动方也发送了FIN,主动方接收到了FIN之后,发送ACK给被动方),主动方会由FIN_WAIT_1 进入此状态,等待被动方返回ACK。
  • TIME_WAIT:从状态变迁图会看到,四次挥手操作最后都会经过这样一个状态然后进入CLOSED状态。共有三个状态会进入该状态

    由CLOSING进入:同时发起关闭情况下,当主动端接收到ACK后,进入此状态,实际上这里的同时是这样的情况:客户端发起关闭请求,发送FIN之后等待服务器端回应ACK,但此时服务器端同时也发起关闭请求,也发送了FIN,并且被客户端先于ACK接收到。
    由FIN_WAIT_1进入:发起关闭后,发送了FIN,等待ACK的时候,正好被动方(服务器端)也发起关闭请求,发送了FIN,这时客户端接收到了先前ACK,也收到了对方的FIN,然后发送ACK(对对方FIN的回应),与CLOSING进入的状态不同的是接收到FIN和ACK的先后顺序。
    由FIN_WAIT_2进入:这是不同时的情况,主动方在完成自身发起的主动关闭请求后,接收到了对方发送过来的FIN,然后回应 ACK。
下面来看看这个看似有点多余的TIME_WAIT状态:从上面进入TIME_WAIT状态的三个状态动作来看(可以直接看状态变迁图)都是主动方最后回应一个ACK(CLOSING实际上前面的那个FIN_WAIT_1状态就已经回应了ACK)。

  先考虑这样的一个情况,假如这个最后回应的ACK丢失了,也就是服务器端接收不到这个ACK,那么服务器将继续发送它最终的那个FIN,因此客户端必须维护状态信息(TIME_WAIT)允许它重发最后的那个ACK。如果没有这个TIME_WAIT状态,客户端处于CLOSED状态(开头就说了CLOSED状态实际并不存在,是我们为了方便描述假想的),那么客户端将响应RST,服务器端收到后会将该RST分节解释成一个错误,也就不能实现最后的全双工关闭了(可能是主动方单方的关闭)。所以要实现TCP全双工连接的正常终止(两方都关闭连接),必须处理终止过程中四个分节任何一个分节的丢失情况,那么主动关闭连接的主动端必须维持TIME_WAIT状态,最后一个回应ACK的是主动执行关闭的那端。从变迁图可以看出,如果没有TIME_WAIT状态,我们将没有任何机制来保证最后一个ACK能够正常到达。前面的FIN,ACK正常到达均有相应的状态对应。

  还有这样一种情况,如果目前的通信双方都已经调用了 close(),都到达了CLOSED状态,没有TIME_WAIT状态时,会出现这样一种情况,现在有一个新的连接被建立起来,使用的IP地址和端口和这个先前到达了CLOSED状态的完全相同,假定原先的连接中还有数据报残存在网络之中,这样新的连接建立以后传输的数据极有可能就是原先的连接的数据报,为了防止这一点,TCP不允许从处于TIME_WAIT状态的socket 建立一个连接。处于TIME_WAIT状态的 socket 在等待了两倍的MSL时间之后,将会转变为CLOSED状态。这里TIME_WAIT状态持续的时间是2MSL(MSL是任何IP数据报能够在因特网中存活的最长时间),足以让这两个方向上的数据包被丢弃(最长是2MSL)。通过实施这个规则,我们就能保证每成功建立一个TCP连接时,来自该连接先前化身的老的重复分组都已经在网络中消逝了。

综上来看:TIME_WAIT存在的两个理由就是

  •   可靠地实现TCP全双工连接的终止;
  •   允许老的重复分节(数据报)在网络中消逝。

TIME_WAIT进一步解析

TCP结束的过程如下:

Server                             Client

-------------- FIN -------------->  server: fin_wait_1

<------------- ACK --------------- client: close_wait  server:fin_wait_2

<------------- FIN  --------------- client发出fin之后就关闭

-------------- ACK ------------->  server发出ack后进入time_wait状态

Time_Wait的默认时间是2倍的MLS,就是240秒钟。MLS是TCP片在网上的最长存活时间。
TIME_Wait的主要作用是保证关闭的TCP端口不立即被使用。因为当网络存在延迟时,可能当某个端口被关闭后,网络中还有一些重传的TCP片在发向这个端口,如果这个端口立即建立新的TCP连接,则可能会有影响。所以使用2倍的MSL时间来限制这个端口立即被使用

  现在的问题在于,4分钟的时间有点长。
  因此,Time_wait的影响,我想,首先每个TCP连接都各自有个数据结构,叫TCP Control Block.Time_wait的时候这个数据结构没有被释放。所以当有太多的TCP连接时,内存可能会被占用很多

  每个TCP报文在网络内的最长时间,就称为MSL(Maximum Segment Lifetime),它的作用和IP数据包的TTL类似

  进入TIME_WAIT状态的一般情况下是客户端,大多数服务器端一般执行被动关闭,不会进入TIME_WAIT状态,当在服务器端关闭某个服务再重新启动时,它是会进入TIME_WAIT状态的

  

  

举例:

  1.客户端连接服务器的80服务,这时客户端会启用一个本地的端口访问服务器的80,访问完成后关闭此连接,立刻再次访问服务器的80,这时客户端会启用另一个本地的端口,而不是刚才使用的那个本地端口。原因就是刚才的那个连接还处于TIME_WAIT状态。

  2.客户端连接服务器的80服务,这时服务器关闭80端口,立即再次重启80端口的服务,这时可能不会成功启动,原因也是服务器的连接还处于TIME_WAIT状态。

3、很多时候,出现大量的TIME_WAIT状态的连接,往往是因为网站程序代码中没有使用mysql.colse(),才导致大量的mysql  TIME_WAIT.

服务器TIME_WAIT过多解决 :

vi /etc/sysctl.conf

编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1 //表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1 //表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 // 1表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout = 30 //修改系統默认的TIMEOUT时间 修改之后,再用命令查看TIME_WAIT连接数
netstat -ae|grep “TIME_WAIT” |wc –l

  

整理自:

  https://blog.csdn.net/wenqian1991/article/details/40110703

  https://blog.csdn.net/gzh0222/article/details/8491178

【TCP】TCP状态的更多相关文章

  1. 查看 Apache并发请求数及其TCP连接状态

    查看 Apache并发请求数及其TCP连接状态 (2011-06-27 15:08:36) 服务器上的一些统计数据: 1)统计80端口连接数 netstat -nat|grep -i "80 ...

  2. 查看 并发请求数及其TCP连接状态【转】

    服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数ps -ef|grep httpd|wc ...

  3. 动手学习TCP:TCP特殊状态

    前面两篇文章介绍了TCP状态变迁,以及通过实验演示了客户端和服务端的正常状态变迁. 下面就来看看TCP状态变迁过程中的几个特殊状态. SYN_RCVD 在TCP连接建立的过程中,当服务端接收到[SYN ...

  4. Linux下查看Web服务器当前的并发连接数和TCP连接状态

    对于web服务器(Nginx.Apache等)来说,并发连接数是一个比较重要的参数,下面就通过netstat命令和awk来查看web服务器的并发连接数以及TCP连接状态. $ netstat -n | ...

  5. 查看 并发请求数及其TCP连接状态

    服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数ps -ef|grep httpd|wc ...

  6. TCP连接状态具体解释

    tcp状态: LISTEN:侦听来自远方的TCPport的连接请求 SYN-SENT:再发送连接请求后等待匹配的连接请求 SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认 ...

  7. TCP连接状态

    TCP 连接状态按 TCP 协议的标准表示法, TCP 可具有如下几种状态,为讨论方便,如下讨论中区分服务端和客户端,实际软件处理上对二者一视同仁. CLOSED关闭状态.在两个通信端使用“三路握手” ...

  8. 查看 Apache并发请求数及其TCP连接状态【转】

    查看 Apache并发请求数及其TCP连接状态 (2011-06-27 15:08:36) 服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80& ...

  9. TCP三次握手及TCP连接状态 TCP报文首部格式

    建立TCP连接时的TCP三次握手和断开TCP连接时的4次挥手整体过程如下图: 开个玩笑 ACK: TCP协议规定,只有ACK=1时有效,连接建立后所有发送的报文ACK必须为1 SYN(SYNchron ...

  10. 关于TCP连接状态的解释

    TCP各个状态主要存在于三次握手和四次挥手的过程 1.TCP建立连接时的三次握手: 服务端应用监听端口处于LISTEN状态,等待建立连接. 第一次握手:客户端发送SYN=一个随机数,然后进入SYN_S ...

随机推荐

  1. [NOIP模拟26]题解

    今天的考试题改自闭了……所以滚来写陈年题解. A.*****贪婪***** RT,出题人告诉我们这题要贪心. 最优的策略一定是拖到必须断的时候再断开(虽然并不知道为什么). 如果一段序列满足题目中的性 ...

  2. 通过create-react-app从零搭建react环境

    一. 快速开始: 全局安装脚手架: $ npm install -g create-react-app 通过脚手架搭建项目: $ create-react-app <项目名称> 开始项目: ...

  3. docker-compose快速搭建 Prometheus+Grafana监控系统

    一.说明Prometheus负责收集数据,Grafana负责展示数据.其中采用Prometheus 中的 Exporter含:1)Node Exporter,负责收集 host 硬件和操作系统数据.它 ...

  4. 【Shiro】三、Apache Shiro认证

    配置好并获取到SecurityManager,代表Shiro正常运行起来了,可以使用Shiro的其它功能. 1.认证流程(API的使用流程) 认证的数据: Principals:标识 ·识别Subje ...

  5. 深入浅出C语言中的柔性数组

    在日常的编程中,有时候需要在结构体中存放一个长度动态的字符串,一般的做法,是在结构体中定义一个指针成员,这个指针成员指向该字符串所在的动态内存空间,例如: typedef struct test { ...

  6. TI推出一款强大模拟设计与仿真工具TINA-TI 9.

    德州仪器 (TI) 宣布推出一款基于 SPICE 的强大模拟设计与仿真工具 TINA-TI 9.1.该免费软件程序的最新版本与 7.0 版相比速度平均提高 5 倍,可帮助工程师在无任何节点或器件数量限 ...

  7. MySQL-视图上进行增删改查

    https://dev.mysql.com/doc/refman/5.7/en/view-updatability.html https://dev.mysql.com/doc/refman/8.0/ ...

  8. 使用密码登陆Amazon EC2

    用的是亚马逊推荐的系统:Amazon Linux AMI 2015.09.1 (HVM) 创建instance后,会有一个pem的key使用该密钥登陆到服务器上后,默认用户名为 ec2-user 直接 ...

  9. Cocos2d-x之引擎框架简介

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 1.cocos2d-x的设计思想 cocos2d-x分为导演,场景,图层,精灵,节点: (1).导演(Director):控制整个游戏的场 ...

  10. 树的重心(DFS)

    ;vector< ; i < v[node].size() ; i++){ , ; i <= n- ; i++){ cin >> a >> b; v[a].p ...