读懂TCP状态转移过程,对理解网络编程颇有帮助,本文将对TCP状态转移过程进行介绍,但各状态(总共11个)含义不在本文介绍的范围,请参考文末的书目列表。

TCP状态转换图(state transition diagram)

1. 建立连接(three-way hand shake)

  • 主动打开(passive open):服务器必须准备好接受外来的连接,通常通过socket、bind和listen完成。
  • 被动打开(active open):客户端通过connect发起主动打开。

插句话,该文介绍的性能分析工具(sar -n TCP,ETCP 1)命令可以对主动打开和被动打开的数目进行统计,在一定程度上可以反应服务器的繁忙程度。

下图给出客户端与服务器的三次握手过程:

  1. 服务器准备好接受外来连接,通常通过socket、bind和listen完成。(服务器:CLOSED->LISTEN)
  2. 客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器客户端将在待建立连接发送数据的初始序列号。(客户端:CLOSED->SYN_SENT)
  3. 服务器端必须ACK客户端SYN,同时发送一个SYN,告诉客户端,服务器将在待建立连接发送数据的初始序列号。(服务器:SYN_RCVD)
  4. 客户端必须ACK服务器SYN。(客户端:SYN_SENT->ESTABLISHED)
  5. 服务器接收到客户端ACK。(服务器:SYN_RECV->ESTABLISHED)

下图给出三次握手对应的状态转移图:

2. 建立连接(同时打开simultaneous open)

参考《TCP/IP详解》卷一第18章18.8节。这种情况发生在两端几乎同时发送SYN并且这两个SYN在网络中交错的情形。这种情况可能发生,但是非常罕见。

例如,主机A的应用程序使用本地端口7777,并与主机B的端口8888执行主动打开。主机B的应用程序使用本地端口8888,并与主机A的端口7777执行主动打开。

下图给出同时打开过程:

下图给出同时打开的状态转移图:

说明:从目前个人经验来看,这种场景没有遇到过,但这是完整理解TCP状态转移必须的一部分。但《TCP/IP详解》卷一第18章18.8节中支出,许多伯克利版的TCP实现都不能正确地支持打开。

3. 建立连接失败(1)

考虑场景:客户端尚未接收到服务器ACK+SYN,异常退出(崩溃退出)。这时,当客户端接收到服务器的ACK+SYN时,客户端回复RST(reset)。此时服务器处于SYN_RCVD状态,当接收到客户端RST时,则从SYN_RCVD转移到LISTEN状态。

具体过程:

  1. 服务器准备好接受外来连接,通常通过socket、bind和listen完成。(服务器:CLOSED->LISTEN)
  2. 客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器,客户端将在待建立连接发送数据的初始序列号。然后客户端异常退出。(客户端:CLOSED->SYN_SENT,然后突然crash,则退出SYN_SENT)
  3. 服务器端ACK客户端SYN,同时发送一个SYN,告诉客户端,服务器将在待建立连接发送数据的初始序列号。(服务器:SYN_RCVD)
  4. 客户端找不到服务器ACK+SYN对应的SYN_SENT状态的socket,则响应RST。(服务器:SYN_RCVD->LISTEN)

下图给出建立连接失败的状态转移图:

4. 建立连接失败(2)

考虑场景1:服务器的进程异常退出,客户端不知道。那么客户端发送SYN后,服务器端响应RST,则客户端建立连接失败。

考虑场景2:服务器机器关闭,导致服务器IP不可达。那么客户端发送SYN后,超时重发,超过重试次数,最终TIMEOUT,则客户端建立连接失败。

具体过程:

  1. 假设服务器进程退出。(服务器:LISTEN->CLOSED)
  2. 客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器,客户将在待建立连接发送数据的初始序列号。(客户端:CLOSED->SYN_SENT)
  3. 服务器端收到客户端SYN,响应RST(服务器:CLOSED)
  4. 客户收到RST。(客户端:SYN_SENT->CLOSED)

下图给出建立连接失败的状态转移图:

5. 断开连接(四次挥手)

  • 主动关闭(active close):某个应用程序首先调用close,发送一个FIN包。
  • 被动关闭(passive close):接收到FIN的对端执行被动关闭。

下图给出客户端与服务器的四次挥手过程:

  1. 某个应用程序首先调用close,该端发送一个FIN包,表示数据发送完毕,该应用程序再无更多数据发送给对端。(例如HTTP服务器发送Reponse数据给client后,再无多余数据发送,则Server可以执行主动关闭)(主动端:ESTABLISHED->FIN_WAIT_1)
  2. 接收到FIN的对端执行被动关闭。首先ACK这个收到的FIN包。该FIN包的接收也作为一个文件结束符(EOF)传递给应用程序(放在已排队等候该应用进程接收的任何其他数据之后),因为FIN包意味着接收端应用进程在相应的连接上再无额外数据可接收。(被动端:ESTABLISHED->CLOSE_WAIT,主动端:FIN_WAIT_1->FIN_WAIT_2)
  3. 一段时间后,接收到这个EOF的应用进程将调用close关闭socket。这导致它的TCP也发送一个FIN包。(被动端:CLOSE_WAIT->LAST_WAIT)
  4. 接收这个最终FIN的执行主动关闭的那一端ACK这个FIN。(被动端:LAST_WAIT->CLOSED,主动端:FIN_WAIT_2->TIME_WAIT(2MSL之后,TIME_WAIT->CLOSED))

下图给出四次挥手的状态转移图:

6. 断开连接(同时关闭simultaneous close)

参考《TCP/IP详解》卷一第18章18.9节。我们在前面讨论了一方(通常但不总是客户方)发送第一个FIN执行主动关闭。双方都执行主动关闭也是可能的,TCP协议也允许这样的同时关闭(simultaneous close)。

下图给出同时关闭过程:

下图给出同时关闭的状态转移图:

7. 断开连接(在FIN_WAIT_1状态中,接收FIN+ACK)

考虑场景:被动关闭端收到FIN包后,直接发送FIN+ACK,则主动关闭方则从FIN_WAIT_1跳过FIN_WAIT_2,直接进入TIME_WAIT。

给出具体流程:

  1. 某个应用程序首先调用close,该端发送一个FIN包,表示数据发送完毕,该应用程序再无更多数据发送给对端。(例如HTTP服务器发送Reponse数据给client后,再无多余数据发送,则Server可以执行主动关闭)(主动端:ESTABLISHED->FIN_WAIT_1)
  2. 接受到FIN的对端执行被动关闭。收到FIN包之后,被动端调用close关闭socket,则FIN+ACK同时发给主动端。(被动端:ESTABLISHED->CLOSE_WAIT->LAST_ACK,主动端:FIN_WAIT_1->TIME_WAIT)
  3. 接收这个最终FIN的执行主动关闭的那一端ACK这个FIN。(被动端:LAST_WAIT->CLOSED,主动端:FIN_WAIT_1->TIME_WAIT(2MSL之后,TIME_WAIT->CLOSED))

下图给出同时关闭的状态转移图:

参考:

  1. 中文版《UNIX网络编程》第一卷第2章
  2. 中文版《TCP/IP详解》卷一第18章

错误说明:

  1. 中文版《UNIX网络编程》第一卷(第三版)(第一次印刷版)图2.4有个错误,服务器从LISTEN转移到SYN_RCVD时,条件应该是“接收:SYN;发送:SYN,ACK”,而不是“接收:RST;发送:SYN,ACK”。这一点可以从英文原本的配图看到。(注:2015年8月第二次印刷已经修订这个错误)
  2. 我也认为,书中的TCP状态转移图中,SYN_RCVD转移到LISTEN的条件应该是服务器状态,而非客户端状态

关于作者:

限于本人对某些技术点的理解程度(虽然也查了很多资料),可能某些地方表达的不太准确,敬请指教,联系方式为pengfeicui@yeah.net。

读懂TCP状态转移的更多相关文章

  1. 使用 tcpdump 抓包分析 TCP 三次握手、四次挥手与 TCP 状态转移

    目录 文章目录 目录 前文列表 TCP 协议 图示三次握手与四次挥手 抓包结果 抓包分析 TCP 三次握手 数据传输 四次挥手 TCP 端口状态转移 状态转移 前文列表 <常用 tcpdump ...

  2. 一篇带你读懂TCP之“滑动窗口”协议

    前言 你现在的努力,是为了以后有更多的选择. 在上一篇文章通过"表白"方式,让我们快速了解网络七层协议了解了网络七层协议. 接下来我们要把重心放在网络传输的可靠性上面.一起来看TC ...

  3. 五分钟带你读懂 TCP全连接队列(图文并茂)

    爱生活,爱编码,微信搜一搜[架构技术专栏]关注这个喜欢分享的地方. 本文 架构技术专栏 已收录,有各种视频.资料以及技术文章. 一.问题 今天有个小伙伴跑过来告诉我有个奇怪的问题需要协助下,问题确实也 ...

  4. 一片非常有趣的文章 三分钟读懂TT猫分布式、微服务和集群之路

    原文http://www.cnblogs.com/smallSevens/p/7501932.html#3782600 三分钟读懂TT猫分布式.微服务和集群之路   针对新手入门的普及,有过大型网站技 ...

  5. 【一起来烧脑】读懂HTTP知识体系

    背景 读懂HTTP很重要,参加过面试的小伙伴都很清楚,无论是技术面试面试题出得怎样,都有机会让你讲解一下HTTP,大部分都会问一下. 面试官:考考你网络协议的知识,TCP协议和UDP协议的区别,HTT ...

  6. 一文读懂HTTP/2及HTTP/3特性

    摘要: 学习 HTTP/2 与 HTTP/3. 前言 HTTP/2 相比于 HTTP/1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性能优化工作,当然兼容问题以及如何 ...

  7. 从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

    本文原作者阮一峰,作者博客:ruanyifeng.com. 1.引言 HTTP 协议是最重要的互联网基础协议之一,它从最初的仅为浏览网页的目的进化到现在,已经是短连接通信的事实工业标准,最新版本 HT ...

  8. 一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm)

    一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm) 2017-12-25  16:29:19   对于 A3C 算法感觉自己总是一知半解,现将其梳理一下,记录在此,也 ...

  9. 一篇文章,读懂Netty的高性能架构之道

    一篇文章,读懂Netty的高性能架构之道 Netty是由JBOSS提供的一个java开源框架,是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,作为一个异步NIO框架, ...

随机推荐

  1. div中文字上下居中

    <div class="title">Title</div> 1. 将div高度设成定值 2. 将line-height设成定值 3. 将text-alig ...

  2. Linux下切换使用两个版本的JDK

    Linux下切换使用两个版本的JDK 我这里原来已经配置好过一个1.7版本的jdk. 输出命令: java -version [root@hu-hadoop1 sbin]# java -version ...

  3. CP-ABE的使用

    参考: http://acsc.cs.utexas.edu/cpabe/tutorial.html http://acsc.cs.utexas.edu/cpabe/ 事先先配置好cp-abe:http ...

  4. zk 创建瞬时、顺序节点的原理

    命令: create -s -e /worker/lock xx zk 的实现代码在:PrepRequestProcessor.pRequest2Txn 中 //The number of chang ...

  5. nodejs sequelize 对应数据库操作符的定义

    const Op = Sequelize.Op [Op.and]: {a: } // 且 (a = 5) [Op.or]: [{a: }, {a: }] // (a = 5 或 a = 6) [Op. ...

  6. cpu占用过高排查

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器 内容解释: PID:进程的ID USER:进程所有者 PR:进程的优先级别,越小 ...

  7. Test22455

  8. vs2015如何使用附加进程调试发布在IIS上项目

    1.如何使用附加进程调试IIS上的网站项目 1)在IIS部署一个网站项目 2)保证浏览器可访问(比如访问登陆页面) 3)在项目中LoginController断点,并在工具栏的调试找到附加到进程 4) ...

  9. 内联函数inline的用法

    一.什么是内联函数 在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗.为了解决这个问题,特别的引入了inline修饰符,表示为内联函数.  栈空间就是指放 ...

  10. 查看json数据更新情况

    #! python3 # -*- coding:utf8 -*- #主要为读取excel中接口地址,打开网页爬取url页面中数据,解析json,检查是否符合逻辑(正常) import requests ...