关于tcp:抓包分析-TCP-握手和挥手

7次阅读

共计 2966 个字符,预计需要花费 8 分钟才能阅读完成。

前言

首先须要明确的是 TCP 是一个 牢靠传输协定 ,它的所有特点最终都是为了这个牢靠传输服务。在网上看到过很多文章讲 TCP 连贯的 三次握手 和断开连接的 四次挥手 ,然而都太过于实践,看完感觉总是似懂非懂。重复思考过后,感觉我本人还是偏工程型的人,要学习这些理论性的常识,最好的形式还是要通过理论案例来了解,这样才会具象粗浅。本文通过 Wireshark 抓包来剖析 TCP 三次握手 四次挥手,如果你也对这些实践感觉似懂非懂,那么强烈建议你也联合抓包实际来强化了解这些理论性的常识。

三次握手

TCP 建设连贯的三次握手是连贯的单方协商确认一些信息(Sequence number、Maximum Segment Size、Window Size 等),Sequence number 有两个作用:一个是 SYN 标识位为 1 时作为初始序列号(ISN),则理论第一个数据字节的序列号和相应 ACK 中的确认号就是这个序列号加 1;另一个是 SYN 标识位为 0 时,则是以后会话的 segment(传输层叫 segment,网络层叫 packet,数据链路层叫 frame)的第一个数据字节的累积序列号。Maximum Segment Size 简称 MSS,示意最大一个 segment 中能传输的信息(不含 TCP、IP 头部)。Window Size 示意发送方接管窗口的大小。上面看看我在本地拜访博客 mghio 的三次握手过程:

图中三个小红框示意与服务器建设连贯的三次握手。

  1. 第一步,client 端(这个示例也就是浏览器)发送 SYN 到 server 端;
  2. 第二步,server 端收到 SYN 音讯后,回复 SYN + ACK 到 client 端,ACK 示意曾经收到了 client 的 SYN 音讯;
  3. 第三步,client 端收到回复 SYN + ACK 后,也回复一个 ACK 示意收到了 server 端的 SYN + ACK 了,其实

到这一步,client 端的 60469 端口曾经是 ESTABLISHED 状态了。
能够看到,其实三次握手的外围目标就是单方相互告知对象本人的 Sequence number,蓝框是 client 端的初始 Sequence number 和 client 端回复的 ACK,绿框是 server 端的初始 Sequence number 和 client 端回复的 ACK。这样协商好初始 Sequence number 后,发送数据包时发送端就能够判断丢包和进行丢包重传了。

三次握手还有一个目标是协商一些信息(上图中黄色方框是 Maximum Segment Size,粉色方框是 Window Size)。

到这里,就能够晓得平时所说的 建设 TCP 连贯 实质是为了实现 TCP 牢靠传输做的前置筹备工作,实际上物理层并没有这个连贯在那里。TCP 建设连贯之后时领有和保护一些状态信息,这个状态信息就蕴含了 Sequence number、MSS、Window Size 等,TCP 握手就是协商进去这些初始值。而这些状态才是咱们平时所说的 TCP 连贯的实质。因为这个太重要了,我还要再次强调一下,TCP 是一个牢靠传输协定,它的所有特点最终都是为了这个牢靠传输服务

四次挥手

上面再来看看,当敞开浏览器页面是产生断开连接的四次挥手过程:

置信你曾经发现了,上图抓包抓到的不是四次挥手,而是三次挥手,这是为何呢?

这是因为 TCP 的时延机制(因为零碎内核并不知道利用能不能立刻敞开),当被挥手端(这里是 server 的 443 端口)第一次收到挥手端(这里是 client 的 63612 端口)的 FIN 申请时,并不会立刻发送 ACK,而是会通过一段延迟时间后再发送,然而此时被挥手端也没有数据发送,就会向挥手端发送 FIN 申请,这里就可能造成被挥手端发送的 FIN 与 ACK 一起被挥手端收到,导致呈现第二、三次挥手合并为一次的景象,也就最终呈现出“三次挥手”的状况。

断开连接四次挥手分为如下四步(假如没有呈现挥手合并的状况):

  1. 第一步,client 端被动发送 FIN 包给 server 端;
  2. 第二步,server 端回复 ACK(对应第一步 FIN 包的 ACK)给 client,示意 server 晓得 client 端要断开了;
  3. 第三步,server 端发送 FIN 包给 client 端,示意 server 端也没有数据要发送了,能够断开了;
  4. 第四步,client 端回复 ACK 包给 server 端,示意既然双发都已发送 FIN 包示意能够断开,那么就真的断开了啊。

上面是 TCP 连贯流转状态图(其中 CLOSED 状态是虚构的,实际上并不存在),这个图很重要,记住这个图后基本上所有的 TCP 网络问题就能够解决。

其中比拟难以了解的是 TIME_WAIT 状态,被动敞开的那一端会经验这个状态。这一端停留在这个状态的最长工夫是 Maximum segment lifetime(MSL)的 2 倍,大部分时候被简称之为 2MSL。存在 TIME_WAIT 状态有如下两个起因:

  1. 要牢靠的实现 TCP 全双工连贯终止;
  2. 让老的反复 segment 在网络中隐没(一个 sement 在网络中存活的最长工夫为 1 个 MSL,一来一回就是 2 MSL);

为什么握手是三次,而挥手是四次?

嘿嘿,这是个经典的面试题,其实大部分人都背过挥手是四次的起因:因为 TCP 是全双工(双向)的,所以回收须要四次 ……。然而再反诘下:握手也是双向的,然而为什么是只有三次呢?

网上流传的材料都说 TCP 是双向的,所以回收须要四次,然而握手也是双向(握手单方都在告知对方本人的初始 Sequence number),那么为什么就不必四次握手呢?所以凡事须要多问几个为什么,要有摸索和狐疑精力。

你再认真回看下面三次握手的第二步(SYN + ACK),其实是能够拆分为两步的:第一步回复 ACK,第二步再发 SYN 也是齐全能够的,只是效率会比拟低,这样的话三次握手不也变成四次握手了。

看起来四次挥手次要是收到第一个 FIN 包后独自回复了一个 ACK 包这里多了一次,如果能像握手那样也回复 FIN + ACK 那么四次挥手也就变成三次了。这里再贴一下下面这个挥手的抓包图:

这个图中第二个红框就是 server 端回复的 FIN + ACK 包,这样四次挥手变成三次了(如果一个包算一次的话)。这里应用四次挥手起因次要是:被动敞开端在收到 FIN 后,晓得被动敞开端要敞开了,而后零碎内核层会告诉应用层要敞开,此时应用层可能还须要做些敞开前的筹备工作,可能还有数据没发送完,所以零碎内核先回复一个 ACK 包,而后等应用层筹备好了被动调 close 敞开时再发 FIN 包。

而握手过程中就没有这个筹备过程了,所以能够立刻发送 SYN + ACK(在这里的两步合成一步了,提高效率)。挥手过程中零碎内核在收到对方的 FIN 后,只能 ACK,不能被动替利用来 FIN,因为零碎内核并不知道利用能不能立刻敞开。

总结

TCP 是一个很简单的协定,为了实现牢靠传输以及解决各种网络传输中的 N 多问题,有一些很经典的解决方案,比方其中的网络拥塞控制算法、滑动窗口、数据重传等。强烈建议你去读一下 rfc793 和 TCP/IP 详解 卷 1:协定 这本书。

如果你是那些纯看实践就能把握好一门技能,而后还能举三反一的人,那我很拜服你;如果不是,那么学习理论知识留神要联合实际来强化了解实践,要通过反反复复能力比拟好地把握一个常识,考究技巧,必要时要学会通过工具来达到目标。

最初 TCP 所有个性基本上外围都是为了 实现牢靠传输 这个指标来服务的,而后有一些是出于优化性能的目标。

正文完
 0