用最通俗的语言讲解 TCP “三次握手,四次挥手”

news2024/12/26 14:48:11

目录

一. 前言

二. TCP 报文的头部结构

三. 三次握手

3.1. 三次握手过程 

3.2. 为什么要三次握手

四. 四次挥手

4.1. 四次挥手过程

4.2. 为什么要四次挥手

五. 大白话说

5.1. 大白话说三次握手

5.2. 大白话说四次挥手

六. 总结


一. 前言

    TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如IP 地址、端口号等。TCP 可以看成是一种字节流,它会处理 IP 层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在 TCP 头部。一个 TCP 连接由一个4元组构成,分别是两个 IP 地址和两个端口号。一个 TCP 连接通常分为三个阶段:连接、数据传输、退出(关闭)。通过三次握手建立一个链接,通过四次挥手来关闭一个连接。当一个连接被建立或被终止时,交换的报文段只包含 TCP 头部,而没有数据。

    所谓“任 TCP 虐我千百遍,我仍待 TCP 如初恋”。“不管面试 Java 、C/C++、Python 等开发岗位, TCP 的知识点可以说是的必问的了。我们都知道TCP是面向连接的,三次握手就是用来建立连接的,四次挥手就是用来断开连接的。

二. TCP 报文的头部结构

在了解 TCP 连接之前先来了解一下 TCP 报文的头部结构:

TCP Header

上图中有几个字段需要重点介绍下:
(1)序号:seq 序号,占32位,用来标识从 TCP 源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:ack 序号,占32位,只有 ACK 标志位为1时,确认序号字段才有效,ack=seq+1。
(3)标志位:共6个,即 URG、ACK、PSH、RST、SYN、FIN 等,具体含义如下:

  1. ACK:确认序号有效。
  2. FIN:释放一个连接。
  3. PSH:接收方应该尽快将这个报文交给应用层。
  4. RST:重置连接。
  5. SYN:发起一个新连接。
  6. URG:紧急指针(urgent pointer)有效。需要注意的是:不要将确认序号 ack 与标志位中的ACK 搞混了。确认方 ack= 发起方 seq+1,两端配对。

三. 三次握手

    三次握手的本质是确认通信双方收发数据的能力。首先,我让信使运输一份信件给对方,对方收到了,那么他就知道了我的发件能力和他的收件能力是可以的。于是他给我回信,我若收到了,我便知道我的发件能力和他的收件能力是可以的,并且他的发件能力和我的收件能力是可以。然而此时,他还不知道他的发件能力和我的收件能力到底可不可以,于是我最后回馈一次,他若收到了,他便清楚了他的发件能力和我的收件能力是可以的。这,就是三次握手。

3.1. 三次握手过程 

我们来看一下三次握手的过程:

1. 准备阶段

    一开始,客户端和服务端都处于 CLOSED 状态。客户端主动打开连接,服务端被动打卡连接,结束CLOSED 状态,开始监听,进入 LISTEN 状态。

2. 第一次握手

    客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1 ,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。

3. 第二次握手

    服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。

4. 第三次握手

    客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。

好了,经过三次握手的过程,客户端和服务端之间的确定连接正常,接下来进入 ESTABLISHED 状态,服务端和客户端就可以快乐地通信了。

这里有个动态过程的图示:

这里有个小细节,第三次握手是可以携带数据的,这是面试常问的点。 

3.2. 为什么要三次握手

为什么要三次握手呢?两次不行吗?

  1. 为了防止服务器端开启一些无用的连接增加服务器开销
  2. 防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

由于网络传输是有延时的(要通过网络光纤和各种中间代理服务器),在传输的过程中,比如客户端发起了 SYN=1 的第一次握手。

如果服务器端就直接创建了这个连接并返回包含 SYN、ACK 和 Seq 等内容的数据包给客户端,这个数据包因为网络传输的原因丢失了,丢失之后客户端就一直没有接收到服务器返回的数据包。

如果没有第三次握手告诉服务器端客户端收的到服务器端传输的数据的话,服务器端是不知道客户端有没有接收到服务器端返回的信息的。服务端就认为这个连接是可用的,端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。 

这样一来,就会有很多无效的连接端口白白地开着,导致资源的浪费。 

这个过程可理解为:

还有一种情况是:已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误:

所以我们需要“第三次握手”来确认这个过程: 
    通过第三次握手的数据告诉服务端,客户端有没有收到服务器“第二次握手”时传过去的数据,以及这个连接的序号是不是有效的。若发送的这个数据是“收到且没有问题”的信息,接收后服务器就正常建立 TCP 连接,否则建立 TCP 连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求发生的错误。

四. 四次挥手

4.1. 四次挥手过程

还是先上图:

四次挥手

聚散终有时,TCP 断开连接是通过四次挥手方式。双方都可以主动断开连接,断开连接后主机中的「资源」将被释放。

上图是客户端主动关闭连接:

第一次挥手:

    客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。

第二次挥手:

    服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。

第三次挥手:

    客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。

第四次挥手:

1. 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态;
2. 服务器收到了 ACK 应答报文后,就进入了 CLOSED 状态,至此服务端已经完成连接的关闭;
3. 客户端在经过 2MSL 一段时间后,自动进入 CLOSED 状态,至此客户端也完成连接的关闭。

你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手

4.2. 为什么要四次挥手

为什么要挥手四次?

再来回顾下四次挥手双方发 FIN 包的过程,就能理解为什么需要四次了。

  1. 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
  2. 服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。

从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。

为什么客户端在 TIME-WAIT 阶段要等 2MSL?

    为的是确认服务器端是否收到客户端发出的 ACK 确认报文,当客户端发出最后的 ACK 确认报文时,并不能确定服务器端能够收到该段报文。

所以客户端在发送完 ACK 确认报文之后,会设置一个时长为 2MSL 的计时器。

MSL 指的是 Maximum Segment Lifetime:一段 TCP 报文在传输过程中的最大生命周期。

2MSL 即是服务器端发出为 FIN 报文和客户端发出的 ACK 确认报文所能保持有效的最大时长。

服务器端在 1MSL 内没有收到客户端发出的 ACK 确认报文,就会再次向客户端发出 FIN 报文:

  • 如果客户端在 2MSL 内,再次收到了来自服务器端的 FIN 报文,说明服务器端由于各种原因没有接收到客户端发出的 ACK 确认报文。

客户端再次向服务器端发出 ACK 确认报文,计时器重置,重新开始 2MSL 的计时。

  • 否则客户端在 2MSL 内没有再次收到来自服务器端的 FIN 报文,说明服务器端正常接收了 ACK 确认报文,客户端可以进入 CLOSED 阶段,完成“四次挥手”。 

所以,客户端要经历时长为 2SML 的 TIME-WAIT 阶段;这也是为什么客户端比服务器端晚进入 CLOSED 阶段的原因。 

这里同样有个动态过程的图示:

四次挥手

五. 大白话说

5.1. 大白话说三次握手

在二十年前的农村,电话没有普及,手机就更不用说了,所以,通信基本靠吼。

老张和老王是邻居,这天老张下地了,结果家里有事,热心的邻居老王赶紧跑到村口,开始叫唤老王:

  1. 老王:老张唉!我是老王,你能听到吗?
  2. 老张一听,是老王的声音:老王老王,我是老张,我能听到,你能听到吗?
  3. 老王一听,嗯,没错,是老张:老张,我听到了,我有事要跟你说。

老王:"你老婆要生了,赶紧回家吧!"

老张风风火火地赶回家,老婆顺利地生了个带把的大胖小子。

握手的故事充满了幸福和美满。

5.2. 大白话说四次挥手

假如博主有一个女朋友——只是“假如”,该死的,这不争气的眼泪,怎么止不住地滴在键盘上。

由于博主上班九九六,下班肝博客,导致没有时间陪女朋友,女朋友忍无可忍:

  • 女朋友:臭男人,最近你都不理我,你是不是不爱我了?你是不是外面有别的狗子了?我要和你分手?
  • 沙雕博主一愣,怒火攻心:分手就分手,不陪你闹了,等我把东西收拾收拾。

沙雕博主小心翼翼地装起了自己的青轴机械键盘:

  • 哼,蠢女人,我已经收拾完了,我先滚为敬,再见!
  • 女朋友:滚,滚的远远的,越远越好,我一辈子都不想再见到你。 

唉,挥手的故事总充满了悲伤和遗憾!

六. 总结

    《TCP/IP详解 卷1:协议》有一张TCP状态变迁图,很具有代表性,有助于大家理解三次握手和四次挥手的状态变化。如下图所示,粗的实线箭头表示正常的客户端状态变迁,粗的虚线箭头表示正常的服务器状态变迁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1327053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ebullient开发文档之OTA升级(从TF中升级简洁明了)

一. 简介 这一篇将给大家介绍如何进行OTA升级(esp32s3), 为了简单方便,可操作性强,这次是从TF中读取固件来进行跟新,本来想看看网上有没有参考的,有是有,但绝大多数都是基于官方的例程,甚至贴出来的源码和…

Spring MVC框架支持RESTful,设计URL时可以使用{自定义名称}的占位符@Get(“/{id:[0-9]+}/delete“)

背景:在开发实践中,如果没有明确的规定URL,可以参考: 传统接口 获取数据列表,固定接口路径:/数据类型的复数 例如:/albums/select RESTful接口 - 根据ID获取某条数据:/数据类型的复数/{id} - 例…

mysql,mysqld,数据库的概念理解,为什么要有数据库,主流数据库,mysql架构介绍,存储引擎介绍,sql语句的分类,查看存储引擎(\G)

目录 概念理解 mysql 狭义 广义 CS模式 mysqld 守护进程 (daemon) 数据库服务 数据库 一般 广义上 数据库 为什么要有数据库 主流数据库​​​​​​​ mysql架构 第一层 -- 链接池 第二层 -- 翻译 第三层 -- 存储引擎​​​​​​​ 存储引擎介绍 总结 …

ansible的脚本—playbook剧本

目录 目录 一、playbook 1、简介 2、playbook组成部分: 3、如何编写Playbook? 4、语句的横向/纵向写法 二、playbook实例: 1、playbook模版: 2、playbook的条件判断: 3、playbook中的循环: 4、循…

【已解决】taos时序数据库3.0版本,怎么按照时间分组?

taos数据库中按照时间分组,在2.4版本时候可以直接使用INTERVAL(time_unit)来查询。例如 前面可以直接添加_ts的。但是在3.0版本之后,如果直接使用的话,只会返回count: 没有前面的时间。那么在3.0版本时候,怎么修改呢&a…

Ubuntu18.04、CUDA11.1安装TensorRT

最近想试试推理加速,因为跑的预测有点慢,一开始是打算从数据处理上实现,采用并行数据处理,但是这个有所难度,而且有几张显卡可用,就想着怎么把显卡利用上。而且了解到推理加速后,就先尝试一下看…

Github项目推荐:在线rename

项目地址 GitHub - JasonGrass/rename: 在线文件批量重命名 项目简介 一个开源的在线重命名文件工具。利用了新的浏览器API获取文件句柄,在不上传文件的情况下对文件进行重命名。可以作为前端文件操作api学习范例。 项目截图

HTML5刷题笔记

在 HTML5 中,onblur 和 onfocus 是:事件属性 onblur 和 onfocus 属于焦点事件: onblur:失去焦点 onfocus:获取焦点 HTML5事件window 事件属性 针对 window 对象触发的事件: onafterprint script 文档…

【Chrome】ERR_SSL_PROTOCOL_ERROR问题

文章目录 前言一、下载二、使用步骤总结 前言 Edge升级最新版后,有的https访问不了,报如下错误 发现新版Chrome以及Chromium内核访问nginx ssl时报错,顺着这个思路接着查看到大佬的结论:服务器nginx使用的openssl版本过低&#…

新下载的Redis启动任务管理器不显示服务

遇到问题:刚刚下载的Redis解压后启动,在任务管理器无法找到Redis服务 但是Redis确实是启动的 解答: 那是因为还需要使用管理员的身份打开终端运行安装一次 命令如下: redis-server.exe --service-install redis.windows.conf --…

Ubuntu 常用命令之 reboot 命令用法介绍

📑Linux/Ubuntu 常用命令归类整理 reboot命令在Ubuntu系统中用于重新启动系统。这个命令通常需要管理员权限才能执行。 reboot命令的参数如下 -f 或 --force:强制重启,不调用shutdown -r进行友好重启。-p 或 --poweroff:在重启…

7-1 单身狗(PTA - 数据结构)

由于这道题在留的作业中,排序和查找都有,所以我先写这道题(图的先放放) “单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱。 输入格式: 输入第一行…

【Earth Engine】协同Sentinel-1/2使用随机森林回归实现高分辨率相对财富(贫困)制图

目录 1 简介与摘要2 思路3 效果预览4 代码思路5 完整代码6 后记 1 简介与摘要 最近在做一些课题,需要使用Sentinel-1/2进行机器学习制图。 然后想着总结一下相关数据和方法,就花半小时写了个代码。 然后再花半小时写下这篇博客记录一下。 因为基于多次拍…

二叉搜索树(AVL树,红黑树)+封装

就像学习其他的东西一样,首先我们要知道二叉搜索树的作用和定义是什么! 首先顾名思义,二叉搜索树肯定是被用来为搜索服务的数据结构。 并且它的搜索效率可以达到logN,也就是一百万的数据也只用查找几十次(AVL树可以控制在20次左…

日常工作中常用的抓包工具都有哪些呢?

📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…

电子合同的分类有哪些?

1、从电子合同订立的具体方式的角度,可分为利用电子数据交换订立的合同和利用电子邮件订立的合同; 2、从电子合同标的物的属性的角度,可分为网络服务合同、软件授权合同、需要物流配送的合同等; 3、从电子合同当事人的性质的角度…

使用Gitee中的CI/CD来完成代码的自动部署与发布(使用内网穿透把本地电脑当作服务器使用)

📚目录 📚简介:⚙️ 所需工具:💨内网穿透配置💭工具介绍✨命令安装🎊配置Cpolar🕳️关闭防火墙🥛防火墙端口放行规则(关闭防火墙可以忽略)🍬小章总…

【python】作用域与闭包 || global与nonlocal

python作用域 其他语言的作用域:块级、函数、类、模块、包等由小到大的级别但是python没有块级(if语句块、for语句块),所以if中定义的变量,相当于普通语句 >>> if True: # if语句块没有作用域x …

华为云之ECS云产品快速入门

华为云之ECS云产品快速入门 一、ECS云服务器介绍二、本次实践目标三、创建虚拟私有云VPC1.虚拟私有云VPC介绍2.进入虚拟私有云VPC管理页面3.创建虚拟私有云4.查看创建的VPC 四、创建弹性云服务器ECS——Linux1.进入ECS购买界面2.创建弹性云服务器(Linux)——基础配置步骤3.创建…

如何使用 templ 在 Go 中编写 HTML 用户界面?

关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力! 简介 templ 是一个在 Go 中编写 HTML 用户界面的语言。使用 templ,我们可以创建可呈现 HTML 片段的组件&#xff0c…