目录

前文列表

《常用 tcpdump 抓包方式》

TCP 协议

TCP(Transmission Control Protocol,传输控制协议),是一种面向连接的可靠传输协议,提供可靠(无差错、不丢失、不重复、按顺序)的字节流数据传输服务。在传输效率和可靠性之间选择了后者,所以也具有开销大、传输速度慢的缺点。

TCP 的可靠性传输具有非常复杂的实现细节,包括但不限于:

ACK 确定机制:当接收方接收到数据段后,会返回 ACK 确认。

定时重发:方发送方发送数据段后,会启动定时器,超时未接收到 ACK 确认,会重发该数据段。

数据校验:接收方会对数据段进行数据校验,如果发现数据段有差错,会将该数据段丢弃,等待超时重传。

顺序传输:TCP 字节流会为每个字节排序,确保数据传输顺序的正确性。

滑动窗口:TCP 数据段长度可根据收发双方的缓存、网络等状态而调整。接收方只允许发送方发送接收缓冲区所能接纳的数据,防止缓冲区溢出。

TCP 数据段首部

  • Sequence Number 序列号:字节流中的每个字节都要按序编号,该字段值为本数据段数据部分的第一个字节的序号
  • Acknowledgment Number 确认号:确认序列号
  • Offset 偏移量:数据段首部的长度,字段值为首部长度除以 4
  • Reserved 预留:保留位,供今后使用
  • TCP Flags 标签:标识数据段性质。
  • Window 窗口:标识发送者接收窗口的大小
  • CheckSum 校验值:用于检查数据段在传输过程中是否出现差错
  • Urgent Pointer 紧急指针:当字段值为 1 时生效,标识本数据段具有紧急数据

其中的 TCP Flags 字段,是非常重要的功能标识,占 8 位,分别为:

  • C(CWR)、E(ECE):用于支持 ECN(显示阻塞通告)。
  • U(URGENT):当值为 1 时,标识此数据段有紧急数据(比如紧急关闭),应优先传送,要与紧急指针字段配合使用。
  • A(ACK):仅当字段值为 1 时才有效,建立 TCP 连接后,所有数据段都必须把 ACK 字段值置为 1。
  • P(PUSH):若 TCP 连接的一端希望另一端立即响应,PSH 字段便可以 “催促” 对方,不再等到缓存区填满才发送返回。
  • R(RESET):若 TCP 连接出现严重差错,该字段的值置为 1,表示先断开 TCP 连接,再重连。
  • S(SYN,Synchronize Sequence Numbers):用于建立和释放连接,当字段值为 1 时,表示建立连接。
  • F(FIN):用于释放连接,当字段值为 1 时,表明发送方已经发送完毕,要求释放 TCP 连接。

NOTE:TCP Flags 在整个 TCP 建立/释放连接的过程中都起到了非常重要的标志作用。

图示三次握手与四次挥手

抓包结果

Client IP:172.18.128.204

Server TCP Socket:(10.0.0.128, 80)

抓包分析

TCP 三次握手

  • Step1. 172.18.128.204.62534 > 10.0.0.128.80: Flags [S], cksum 0x8523 (correct), seq 3401804541, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 960632545 ecr 0,sackOK,eol], length 0

客户端执行系统调用 connect() 发出 SYN 请求建立 TCP 连接,此时客户端的 TCP 端口状态为 SYN_SENT(表示请求连接)。

  • Step 2. 10.0.0.128.80 > 172.18.128.204.62534: Flags [S.], cksum 0x378d (incorrect -> 0xf136), seq 2666924726, ack 3401804542, win 27960, options [mss 1410,sackOK,TS val 19959035 ecr 960632545,nop,wscale 7], length 0

服务端执行系统调用 listen() 监听到 SYN 请求,TCP 端口状态从 LISTEN 转为 SYN_RCVD 并第一次响应 ACK。

  • Step 3. 172.18.128.204.62534 > 10.0.0.128.80: Flags [.], cksum 0x7cfb (correct), seq 3401804542, ack 2666924727, win 4106, options [nop,nop,TS val 960632549 ecr 19959035], length 0

客户端接收到 ACK 响应之后,TCP 端口状态变成 ESTABLISHED(已建立连接,表示通信双方正在通信),再给服务端发送 ACK。服务端接收到 ACK 之后,服务端的 TCP 端口状态为 ESTABLISHED。

NOTEFlags are some combination of S (SYN), F (FIN), P (PUSH), R (RST), W (ECN CWR) or E (ECN-Echo), or a single ‘.’ (no flags)

  • options 表示选项

    • mss 表示是发送端通告的最大报文长度
    • sackOK 表示发送端支持 SACK 选项,SACK 选项是为了更好的确定数据的准确接收的
    • TS val 发送端的时间戳 ecr 接收端的时间戳
    • wscale 表示窗口因子大小

为什么需要三次握手来保证数据传输的可靠性

“握手” 的行为实际上为了告知收发双方自己的 ISN(Initial Sequence Number,初始化序号),如上文 Client:seq=996980318 或 Server:seq=2180032179,这个 ISN 会被作为建立连接后进行「顺序」数据传输的依据。我们可以从数据段首部的 Sequence Number 和 Acknowledgment Number 都占 32 位得知,seq 和 ack 的取值范围均是 [0, 2^32-1],所以 ISN 实际上会被顺序循环使用。而且 seq 并非每次都是从 0 开始的,TCP 协议会以 4μs 一次的频率进行 ISN+=1 操作,以此来避免 TCP 重连时出现在同一条连接中存在两个及以上 seq number 相同的数据包,而最终导致顺序错乱。所以,三次握手实际上就是初始化通信双方的 seq ISN,保证数据包的有序传输

数据传输

双方建立通信之后,Client 向 Server 正式发出 HTTP 请求

IP (tos 0x0, ttl 60, id 0, offset 0, flags [DF], proto TCP (6), length 129)
172.18.128.204.62534 > 10.0.0.128.80: Flags [P.], cksum 0xe98f (correct), seq 3401804542:3401804619, ack 2666924727, win 4106, options [nop,nop,TS val 960632549 ecr 19959035], length 77: HTTP, length: 77
GET / HTTP/1.1
Host: 172.18.22.208
User-Agent: curl/7.54.0
Accept: */* IP (tos 0x0, ttl 64, id 34743, offset 0, flags [DF], proto TCP (6), length 52)
10.0.0.128.80 > 172.18.128.204.62534: Flags [.], cksum 0x3785 (incorrect -> 0x8bd8), seq 2666924727, ack 3401804619, win 219, options [nop,nop,TS val 19959040 ecr 960632549], length 0
  • Client => Server:seq = x+1, ack = y+1 继承了第三次连接的 seq 和 ack number
  • 请求长度 length: 77,seq 3401804542:3401804619 == seq 3401804542:[3401804542+length]

Server 处理请求并响应

IP (tos 0x0, ttl 64, id 34744, offset 0, flags [DF], proto TCP (6), length 295)
10.0.0.128.80 > 172.18.128.204.62534: Flags [P.], cksum 0x3878 (incorrect -> 0x528d), seq 2666924727:2666924970, ack 3401804619, win 219, options [nop,nop,TS val 19959044 ecr 960632549], length 243: HTTP, length: 243
HTTP/1.1 200 OK
Date: Thu, 24 Jan 2019 10:08:31 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Thu, 24 Jan 2019 08:26:02 GMT
ETag: "4-5802ff5f8b6b4"
Accept-Ranges: bytes
Content-Length: 4
Content-Type: text/html; charset=UTF-8 123
IP (tos 0x0, ttl 60, id 0, offset 0, flags [DF], proto TCP (6), length 52)
172.18.128.204.62534 > 10.0.0.128.80: Flags [.], cksum 0x7bae (correct), seq 3401804619, ack 2666924970, win 4099, options [nop,nop,TS val 960632560 ecr 19959044], length 0
  • Server => Client:seq S_ISN:[S_ISN+length], ack C_ISN

NOTE 1:在经过了三次握手之后(Client 和 Server 都确定了对方的 seq ISN),正式的 HTTP 数据传输是在有序进行的。

NOTE 2:可以看见每一个数据包的发出都有相应的 ACK 响应,确保接收方有确切的接收到数据包,否则发送方会启用超时重发。

四次挥手

TCP 协议规定,对于已经建立的连接,收发双方要进行四次挥手才能成功断开连接,如果缺少了其中某个步骤,都会使连接处于假死状态,连接本身所占用的资源不会被释放。

  • Step 1. 172.18.128.204.62534 > 10.0.0.128.80: Flags [F.], cksum 0x7bad (correct), seq 3401804619, ack 2666924970, win 4099, options [nop,nop,TS val 960632560 ecr 19959044], length 0

由 Client 提出断开连接请求 FIN(Flags [F.],),Client 的 TCP 端口进入 FIN-WAIT-1 状态。

  • Step 2、3. 10.0.0.128.80 > 172.18.128.204.62534: Flags [F.], cksum 0x3785 (incorrect -> 0x8acb), seq 2666924970, ack 3401804620, win 219, options [nop,nop,TS val 19959053 ecr 960632560], length 0

Server 发送 ACK 应答,Server 的 TCP 端口进入 CLOSE_WAIT 状态,Client 的 TCP 端口进入 FIN-WAIT-2 状态。几乎同时 Server 还发送了一个 FIN 端口连接请求,进入 LAST-ACK 状态。

  • Step 4. 172.18.128.204.62534 > 10.0.0.128.80: Flags [.], cksum 0x7b9a (correct), seq 3401804620, ack 2666924971, win 4099, options [nop,nop,TS val 960632569 ecr 19959053], length 0

Client 进行 ACK 应答(LAST ACK),进入 TIME-WAIT(两倍的分段最大生存期),并最终变成 CLOSED 状态。

TCP 端口状态转移

TCP 协议规定,对于已经建立的连接,收发双方要进行四次挥手才能成功断开连接,如果缺少了其中某个步骤,都会使连接处于假死状态,连接本身所占用的资源不会被释放。实际上,一个网络服务器经常要同时管理大量的并发连接,所以需要保证无用的连接被完全断开,否则大量假死的连接会占用许多服务器资源。

对于这个问题,我们要关注 TCP 端口的:CLOSE_WAIT 和 TIME_WAIT 状态,与 TCP 四次挥手过程密切相关。

可以通过下面方法来查看 TCP 端口状态数量

╭─mickeyfan@localhost  ~
╰─$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 127 ↵
CLOSE_WAIT 1
TIME_WAIT 1
ESTABLISHED 17

状态转移

  • LISTENING:网络服务启动后首先会处于监听的状态

  • SYN_SENT:表示收发方请求建立连接

  • ESTABLISHED:表示成功建立连接,当你要访问其它的计算机的网络服务时首先要发个 SYN 信号到特定端口,此时当前服务器的 TCP 端口状态为 SYN_SENT,如果连接成功了则会变为 ESTABLISHED。

NOTE:SYN_SENT 状态一般非常短暂,但如果发现 SYN_SENT 的数量非常多并且在向不同的网络服务器发出,那当前机器可能中了冲击波或震荡波之类的病毒。这类病毒为了感染别的计算机,它就要扫描别的计算机,在扫描的过程中对每个要扫描的计算机都要发出了 SYN 请求,这也是出现许多 SYN_SENT 的原因。

  • TIME_WAIT:当我方主动执行系统调用 close() 断开连接,并且收到对方的 ACK 确认后,我方的 TCP 端口状态就会变为 TIME_WAIT。

NOTE:TCP 协议规定 TIME_WAIT 状态会一直持续 2MSL(两倍的分段最大生存期,240s),以此来保证重新分配的 Socket 不会受到之前残留的延迟重发报文的影响(保证旧的连接状态不会对新连接产生影响)。处于 TIME_WAIT 状态的连接(Socket)占用的资源不会被内核释放,所以作为网络服务器,在可能的情况下,尽量不要主动断开连接。尤其对于要处理大量短连接的服务器,应该由客户端来主动提出断开,以减少 TIME_WAIT 状态造成的资源浪费。如果发现服务器存在大量的 TIME_WAIT,那么你应该检查是否有大量的自动断开连接动作存在服务器上。还有这样的情况,又我方提出断开连接,但对方一直不给 ACK 应答,我方就会卡在 FIN_WAIT_2 状态,此时我方默认等到 60 秒(可修改,参考 tcp_max_orphans)。所以这种情况下我方内存也会被大量无效数据报填满。

  • CLOSE_WAIT:对方主动关闭连接(或连接异常中断),我方的状态就会变成 CLOSE_WAIT。此时我方会主动调用 close() 来使得连接被正确关闭。

NOTE:CLOSE_WAIT 表示我方被动断开连接,如果存在大量的 CLOSE_WAIT,表示我方只在第二次挥手时向对方应答 ACK,并没有完成第三次挥手,向对方发送 FIN 请求,这时就可能是因为在关闭连接之前网络服务器还有大量的数据要发送或者其他事要做,导致没有发送这个 FIN packet。一般是由网络服务器负载过高,或出现了不可预料的问题导致的。一个 CLOSE_WAIT 会维持至少 2 个小时,如果存在由于负载一直居高不下,生产了大量的 CLOSE_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:表示开启 TCP 连接中 TIME-WAIT Sockets 的快速回收,默认为 0,表示关闭。
  • net.ipv4.tcp_fin_timeout:系統等待 FIN_WAIT 超时时间。

使用 tcpdump 抓包分析 TCP 三次握手、四次挥手与 TCP 状态转移的更多相关文章

  1. [转]Linux服务器上11种网络连接状态 和 TCP三次握手/四次挥手详解

    一.Linux服务器上11种网络连接状态: 图:TCP的状态机 通常情况下:一个正常的TCP连接,都会有三个阶段:1.TCP三次握手;2.数据传送;3.TCP四次挥手. 注:以下说明最好能结合”图:T ...

  2. 网络 TCP三次握手,四次挥手详解

    三次握手,四次挥手可以说是炙手可热的面试题了,来看看它究竟长什么样子吧! 我们先把流程图贴上来 : 为什么这么复杂? 因为TCP是可靠性传输. 确认可靠传输的前提:  TCP连接管理机制 用TCP首部 ...

  3. tcp三次握手四次挥手那些事

    建立TCP需要三次握手才能建立,而断开连接则需要四次挥手.三次握手,四次挥手流程图如下: 一.首先看下如何通过三次挥手----------建立连接 首先客户端发送连接请求报文,服务端接受连接后回复AC ...

  4. TCP三次握手四次挥手,通俗易懂版

    三次握手四次挥手 三次握手 其实很好理解,三次握手就是保证双手都有发送和接受的能力.那么最少三次才能验证完成 即----> 客户端发送---服务端收到----服务端发送-- 1.客户端发送 -- ...

  5. wireshark抓包直观图解 TCP三次握手/四次挥手详解

    转http://www.seanyxie.com/category/linux/ 作者:seanyxie |   一. TCP/IP协议族 TCP/IP是一个协议族,通常分不同层次进行开发,每个层次负 ...

  6. TCP三次握手/四次挥手详解

    一. TCP/IP协议族 TCP/IP是一个协议族,通常分不同层次进行开发,每个层次负责不同的通信功能.包含以下四个层次: 1. 链路层,也称作数据链路层或者网络接口层,通常包括操作系统中的设备驱动程 ...

  7. TCP三次握手四次挥手详解

    转载 http://www.cnblogs.com/zmlctt/p/3690998.html 相对于SOCKET开发者,TCP创建过程和链接折除过程是由TCP/IP协议栈自动创建的.因此开发者并不需 ...

  8. 转---tcp三次握手四次挥手syn fin......

    http://blog.chinaunix.net/uid-22312037-id-3575121.html转自 一.TCP报文格式        TCP/IP协议的详细信息参看<TCP/IP协 ...

  9. TCP 三次握手四次挥手, ack 报文的大小.tcp和udp的不同之处、tcp如何保证可靠的、tcp滑动窗口解释

    一.TCP三次握手和四次挥手,ACK报文的大小 首先连接需要三次握手,释放连接需要四次挥手 然后看一下连接的具体请求: [注意]中断连接端可以是Client端,也可以是Server端. [注意] 在T ...

  10. TCP三次握手/四次挥手

    TCP 三次握手 TCP 连接是通过三次握手进行初始化的.三次握手的目的是同步连接双方的序列号和确认号并交换 TCP 窗口大小信息.以下步骤概述了通常情况下客户端计算机联系服务器计算机的过程: 1.  ...

随机推荐

  1. filepath:处理文件路径的一把好手

    1.ToSlash(path string) string 将相关平台的路径分隔符转为/ package main import ( "fmt" "os" &q ...

  2. Python 3.8测试阶段正式开始,发布Beta 1版

    上周,Python背后的团队宣布发布了Python 3.8.0b1 版本,这是Python 3.8计划的四个beta发行预览版中的第一个.此版本标志着beta阶段的开始,您可以在此阶段测试新特性,并使 ...

  3. AVAYA_Site_administrator软件简单操作

    AVAYA_Site_administrator软件简单操作 1.配置软件(第一次登录) 点击File>New>Voice System  在弹出对话框随意输入一个名称 下一步,默认选择 ...

  4. RE 逆向工程初学者指南:方法和工具

    简评: RE 两种分析,静态.动态.好好分析静态因为能够解决 70 % 的问题.介绍了一些工具和方法.Enjoy yourself. 最近几天,我决定试水逆向工程,即使在计算机和编程相关领域有一定的基 ...

  5. myeclipse 工具栏 Run按钮不见了,怎么调出来啊?

    window-->new window,打开新窗口,按钮出现了.关闭老窗口,再关闭新窗口.再次打开MyEclipse,妥妥的了.

  6. DevExpress ASP.NET Core v19.1版本亮点:数据网格和树列表

    行业领先的.NET界面控件DevExpress 发布了v19.1版本,本文将以系列文章的方式为大家介绍DevExpress ASP.NET Core Controls v19.1中新增的一些控件及增强 ...

  7. node + mongoDB

    在MongoDB安装这篇博客中已经创建了一个bella_blog的数据库,该数据已经包含了user集合. 下面就可以在node sever端用MongoDB了. Mongoose库简而言之就是在nod ...

  8. 微信小程序data数组push和remove问题

    因为在做一个小程序的demo时.由于不向后台请求数据,所以就涉及到对本地数据的操作,现在就做一些数组的增删 //添加新元素 addItemFn: function () { var { lists } ...

  9. 科普TPF知识

    https://tieba.baidu.com/p/4926092734?see_lz=1&pn=1 707680700 https://tieba.baidu.com/p/492609273 ...

  10. 学到了林海峰,武沛齐讲的Day51 django+数据库

    连不上,通过这一步解决 搞死了..辛苦但觉得值得 刷数据库 出问题 IDEA关联MySQL报错:Server returns invalid timezone. Go to ‘Advanced’ ta ...