当前位置: 首页 > backend >正文

网络编程及原理(六):三次握手、四次挥手

目录

一 . TCP 的核心机制:连接管理 

二 . 三次握手:建立连接 

(1) 三次握手的意义 

(1.1)初步验证通信链路是否流畅 

(1.2)确认通信双方各自的发送、接受能力是否正常 

(1.3)双方对关键数据参数的协商 

 (2)为什么一定是三次握手? 

三 . 四次挥手:断开连接 

为什么三次握手能合并,四次挥手不能?

四 . 连接管理全流程 

(1)LISTEN 

(2)ESTABLISHED 

(3)CLOSE _ WAIT 

(4)TIME _ WAIT 


这两周期末考昂,所以更新有丢丢慢,还望诸君见谅,今天继续来说网络编程原理这一板块,这一期主要来聊一聊非常重要的 TCP 核心机制:连接管理 —— “ 三次握手,四次挥手 ”

一 . TCP 的核心机制:连接管理 

现在网上有很多资料显示的是 “ TCP 的可靠性传输,是通过三次握手,四次挥手来保证的 ” ,大家一定一定要注意!这里的这种说法是不准确的,不算完全错误,但是是不够准确的。

TCP 的可靠性传输机制最最最关键的核心是我们的 “ 确认应答 ” 和 “ 超时重传 ” !

三次握手四次挥手这一操作是我们在建立连接时进行的,而后续持续的数据传输,则更重要的是靠我们的确认应答和超时重传。

连接管理主要分为两大部分:建立连接和断开连接。其中建立连接也就是我们的 “ 三次握手 ” ,断开连接也就是我们的 “ 四次挥手 ” 。这里面的次数指的也就是网络通信的次数,握手挥手没有实际意义,只是一种形象的比喻(handshake,计算机中的常用术语),网络中的握手,表示的是不携带业务数据(没有载荷,只有报头)的数据包,只是起到一个 “ 打招呼 ” 的作用。

二 . 三次握手:建立连接 

握手,也就是我们客户端向服务器发起的 syn ,大家注意,这个 syn 是不是感觉很眼熟,有没有回想起之前我们在学习加锁时有一个东西叫 synchornized ,没错,这里的 syn 就是 synchornized,也是同步的意思,但是这一同一术语,在这两处不同的地方,所表达的含义不一样,在计算机领域有着很多看似相同的术语,大家都要结合上下文理解。锁中的同步,含义是 “ 互斥 ” 。

此处的 syn 同步,我们可以理解为是客户端在跟服务器打招呼,希望服务器跟他统一步调,从而能够完成后续的数据传输工作。

当我们这里服务器 B 收到了客户端 A 发来的同步请求 syn ,B 表示同意,所以给客户端 A 回了一个 ack ,并且几乎同时服务器 B 也给 客户端 A 回了一个 syn ,表示我这边也需要跟你同步。

当我们客户端 A 收到了服务器 B 发送的 syn 同步请求,表示同意,也需要回应一个 ack 。经过这一系列请求、回应的操作,客户端和服务器才都能掌握到对方已经同意建立连接的信息。

(1) 三次握手的意义 

我们为啥要进行三次握手呢?三次握手解决了什么问题呢?三次握手的意义何在呢?三次握手主要是为了解决三个方面的问题:

(1.1)初步验证通信链路是否流畅 

这一点很重要,它是进行我们可靠传输(甚至可以说是传输)的 “ 前提条件 ” 。大家应该都坐过地铁吧?很少有人知道的是,在每天的第一班地铁之前,都会先进行一趟 “ 空跑 ” ,就是不载人,先试运用一趟,其目的就是为了验证我们的道路是否安全可通行。

(1.2)确认通信双方各自的发送、接受能力是否正常 

我们的三次握手,不就是一个打完招呼之后等待对方回应的过程嘛,如果我们迟迟没有得到回应,那就可能证明我们的消息并没有有效地发出或者对方收到了我们的消息但是不能发出有效应答。

(1.3)双方对关键数据参数的协商 

在建立连接的过程中,我们是需要对一些后续需要用到的重要数据进行协商的,举个例子:

在我们的 TCP 中 “ 三次握手 ”,有很多的数据需要协商,这里我们只重点讨论一个:

在 TCP 通信时,需要通过三次握手协商确定 “ 起始数据的序号 ”,换言之我们可以知道 TCP 的序号并不是每次都是从 1 开始的,每次建立连接,TCP 的起始序号都会不同,并且会故意相差很大,这是为什么呢?这是为了防止 “ 前朝的剑斩本朝的官 ” ,这是星爷的经典电影《九品芝麻官》里的。

当我们在 A、B 两个主机之间传输数据的时候,我们这一次用完了,但是有没有一种可能,在我们这一次的传输过程中,有那么一个数据包 “ 迷路 ” 了,当我们在下一次再用 A、B 两个主机之间传输数据的时候,此时这一迷路的数据包到达了对端,但是我们现在已经 “ 改朝换代 ” 了啊,我们应该辨别出这个数据是否有效,如果发现这个数据包的序号和我们这次的起始序号还有最近收到的序号差别都特别大的话,就会将其认定为 “ 前朝 ” 的,就需要将其丢弃掉。

 (2)为什么一定是三次握手? 

大家有没有想过一个问题?我们这里为什么是三次握手呢?为什么不能是两次?甚至于四次?

四次是可行的,我们前面说过。中间的一次是将服务器的 syn 和 ack 两个数据包合并在一起成为一个数据包,这是为了提高效率,减少数据包封装、分用的开销,所以四次可以,但是没有必要。

两次不行,因为我们至少要验证通信双方的两种功能是否正常:发送和接受,大家捋一捋就会发现,确定这两种信息最少也得三次,两次就无法完成通信双方针对各自接受与发送能力的验证。

注意:针对 TCP 来说,必须是三次握手,因为我们需要验证通信双方的发送、接收能力。但是在其他协议当中,握手过程可不一定是三次,具体情况具体分析!

三 . 四次挥手:断开连接 

四次挥手就是为了断开连接,但是这并不是我们一般理解的那种说断马上就断开连接,那样子的话根本不用不了四次嘛,这里的断开连接是一种 “ 优雅的 ” 断开,互相通知对方,征求对方同意,好聚好散嘛。

上一期我们在谈到 “ 超时重传 ” 的时候,提到过一种 “ 单方面断开连接 ” ,这就是 A 单方面的直接删除掉储存的 B 的信息,这就很不优雅,这就是一种 “ 粗鲁的 ” 断开连接。

首先,我们的知道,断开连接不一定是 “ 客户端主动 ” ,我们对端服务器也可以主动断开连接。

为什么三次握手能合并,四次挥手不能?

对于三次握手来说,中间的两次 SYN + ACK 都是在系统内核中,由操作系统负责进行的,时机都是在收到 SYN 之后,此时处于同一时机,就可以进行合并。

而对于四次挥手来说,ACK 是系统内核控制的,但是我们 FIN 的触发,则是通过应用程序调用 close()进程退出触发的。

例如我们之前讲到的 TCP 回显服务器中有这么一段:

我们在服务器的 finally 中调用 close(这是服务器中调用的 close),什么时候才能运行到 close 这一块呢?我们在上面有一个循环,需要触发条件结束循环才能够运行到这儿。

这里的重点是循环条件:!scan.hasNext(),这就意味着需要客户端先 close()/ 客户端退出,这俩操作都会触发客户端先给服务器发 FIN 。

那么我们这里就可以看到,从客户端给服务器发 FIN 到我们的服务器调用 finally 中的 close ,这中间还有很多操作,执行很多逻辑,这一过程是很有可能消耗一定时间的,所以我们四次挥手,很大概率是来不及合并的。甚至在某种极端情况下,例如,我们的程序员在服务器代码中忘了写 close ,这个 FIN 都发不出来,就更不可能合并了。

四 . 连接管理全流程 

我们需要注意一下 TCP 的状态转换:

这张图里就囊括了在连接管理的全过程,我们 TCP 详细的状态转换,图中信息太过复杂,我们不需要全部熟知,只需要了解几个重要的状态转换即可:

(1)LISTEN 

服务器进入的状态。也就是当服务器将端口绑定好之后,进入了 Listen 状态,此时意味着服务器已经初始化完毕,准备好随时迎接客户端了。(相当于我们手机开机,信号良好,随时可以接电话)

(2)ESTABLISHED 

这个单词英文原意是 “ 建立 ” ,这是客户端和服务器都会进入的状态,我们在全流程的图中可以看到,当我们客户端和服务器都存有对方信息的时候,就会分别进入这个状态。在这里的意思就是当 TCP 建立完成(也就是保存好对方的信息了),接下来就可以进行业务数据的通信了。(也就相当于,我们电话接通了,可以进行通话交流了)

(3)CLOSE _ WAIT 

被动断开连接的一方,就会进入这个状态。(也就是先收到 FIN 的一方,就会进入到这个状态)这个状态也就是等待我们的代码执行 close 方法。这一段时间,也就是我们不能将 ACK 和 FIN 进行合并的间隔时间。(因为上面说过了嘛,我们是先收到要关闭的请求,然后可能经过一系列的逻辑,直到我们真正地发出 FIN ,大家能理解吗)

这时候有一种情况,那就是我们服务器端,存在大量的 CLOSE_WAIT 状态的 TCP 连接,这说明什么呢?此时,说明服务器代码很可能有 BUG ,我们就需要排查 close 是否写了,或者是否能及时的执行到,是不是陷入死循环了?

(4)TIME _ WAIT 

主动断开连接的一方,就会进入这个状态。此处的 TIME_WAIT 是按照一定时间来等待,达到一定时间之后,连接就会释放。

那么这个时候就会有小伙伴问了,为什么要等待呢?我们直接释放掉不就好了嘛?大家注意,这里的等待是很有必要的,是为了防止最后的 ACK 丢包,( TCP 在传输任何数据的时候都有可能丢包,这是无法避免,无法预见的情况,我们只能随时做好重传和接受重传的准备)因为我们最后的 CLOSE 严格意义上来说,并不能算是一种状态,你想嘛,都关闭了,我们看不到也感知不到它的存在了,何来状态呢?所以我们需要等待一定的时间,如果我们最后的 ACK 丢包了,对方一定时间内没有收到 ACK ,就会重传 FIN ,此时我们如果当即释放了,那不就收不到重传的 FIN 了嘛?

所以我们在保留一段时间之后,没有收到重传的 FIN ,说明刚才的 ACK 应该是到了,此时这里就可以释放了。

TIME_WAIT 存在的时间,我们称之为 2MSL( MSL 就是数据报在网络传输中消耗的最大时间)

OKK,有关于 “ 三次握手,四次挥手 ” 的知识点咱们就讲到这里啦,这一块是非常重要的,大家一定要深入理解,敲黑板!高频面试题!!!好啦,咱们下期再见吧,与诸君共勉!!!

http://www.xdnf.cn/news/14618.html

相关文章:

  • 【软考高级系统架构论文】论NoSQL数据库技术及其应用
  • 通过事件过滤器拦截QRadioButton点击事件
  • 算法第38天|322.零钱兑换\139. 单词拆分
  • 数据分析和可视化:Py爬虫-XPath解析章节要点总结
  • 【Python进阶系列】第9篇:聊聊 Python 中常用的第三方库
  • C++递归应用
  • 7.3.1二叉排序树
  • 【编译原理】语句的翻译
  • FPGA基础 -- Verilog 共享任务(task)和函数(function)
  • VUE3 Element UI el-button type icon
  • King’s LIMS 系统引领汽车检测实验室数字化转型
  • QT历史版本,5.15.2使用清华源半小时安装速成
  • GitHub Actions + SSH 自动部署教程
  • 日常运维问题汇总-24
  • 分清display三个属性
  • MySQL之事务深度解析
  • 为什么你的vue项目连接不到后端
  • 基于微信小程序的美食点餐订餐系统
  • JSON 数据格式详解
  • SEO已死,GEO当立:AI搜索时代的新游戏规则
  • Hollywood: The World’s Most Effective Propaganda System
  • VR 看房:突破成长痛点,展望未来趋势
  • 基于深度学习的智能视频行为识别系统:技术与实践
  • 如何使用 Dockerfile 创建自定义镜像
  • 【LUT技术专题】采样间隔自适应3DLUT-AdaInt
  • 《思维力:高效的系统思维》
  • 《Kubernetes》Pod详解+Pod控制器
  • 计量经济学(复习/自用/未完)
  • OpenAI 公布《走向理解与预防失准泛化:由“角色特征”驱动的突现性失准》研究总结
  • Postman 的 Jenkins 管理 - 自动构建