【网络原理】TCP协议的连接管理机制(三次握手和四次挥手)

系列文章目录

【网络通信基础】网络中的常见基本概念

【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序(万字博文)

【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制(CRC算法、MD5算法)

【网络原理】TCP协议的相关机制(确认应答、超时重传)


文章目录

前言

一、建立连接(三次握手)

建立连接(三次握手)的意义

1)投石问路,确认当前通信路径是否畅通

2)验证通信双方,发送能力和接收能力是否正常

3)三次握手的过程中,通信双方也会协商一些必要的参数

二、断开连接(四次挥手)

三、连接管理过程中涉及到的TCP状态转换


前言

接上文,我们介绍了TCP协议中,保证可靠性传输的核心机制,确认应答和超时重传机制。

TCP协议的连接管理机制,是整个网络原理中,最高频的问题,没有之一!因此,这里单独用一篇博客,详细介绍TCP协议的连接管理机制。

TCP协议的连接管理机制主要包括三次握手建立连接四次挥手断开连接


一、建立连接(三次握手)

在前面的文章中,我们写过TCP回显客户端和服务器程序。

当客户端执行 clientSocket = new Socket(serverIp, serverPort); 这个操作的时候,就是在建立连接。此处只是调用了 socket API,真正连接建立的过程,是由TCP协议完成的。

TCP协议建立连接的这个过程,就称为“三次握手”。

这里谈到的连接,是“虚拟的,抽象的”连接。目的是让通信双方都能保存对方的相关信息。

此处又涉及到六位标志位的其中一位=>SYN,代表同步(synchronize)。所谓的SYN,是一个特殊的,带有SYN标志位的TCP数据包:

  1. 没有载荷,不带有应用层的数据.
  2. 六位标志位的第五位,将该位设置为1.

虽然SYN数据包不带有载荷,但是SYN数据包会包含IP报头(如果在IP网络中传输)或以太网数据帧帧头(如果在以太网中传输),以及TCP报头。这些头部包含了一些必要的信息,比如源IP地址、目标IP地址、源端口、目标端口等。这个过程,也是客户端在告诉服务器,我是谁。

了解了SYN数据包后,再来看下三次握手的大致过程。首先要清楚,客户端是主动的一方,第一次交互,一定有客户端主动发起的:

上图过程中,是有四次交互,简单来说:

  1. 客户端先向服务器发送SYN请求
  2. 服务器回复客户端一个ACK应答报文
  3. 服务器再给客户端发送一个SYN请求
  4. 客户端回复服务器一个ACK应答报文

这个建立连接的过程,本质上就是通信双方各自给对方发起一个SYN,各自给对方回应一个ACK。但实际上,中间的两次交互(2和3),是能够合二为一的。

因为回复一个带ACK标志位的数据包,再回复一个带SYN标志位的数据包,可以合并成一个数据包,这个数据包同时带有ACK标志位和SYN标志位。即第2位(ACK)和第5位(SYN)都为1.

此时这个数据包就同时起到了两个作用,既能应答上个请求,也能发起SYN。

这么做的原因是:网络传输过程中要涉及到多次的封装和分用,两个包合并成一个包,就可以减少一次封装分用的过程,整体的效率就提升了。

经过合并,四次交互也就变成了三次,也就形成了“三次握手”


因此,三次握手的具体过程如下:

  1. 客户端向服务器发送SYN请求: 客户端首先向服务器发送一个带有SYN标志位的数据包,其中包含了客户端的初始序列号(ISN)。

  2. 服务器发送SYN-ACK响应: 服务器收到客户端的SYN请求后,会回复一个带有SYN和ACK标志位的数据包,称为SYN-ACK响应。这个响应中,服务器确认了客户端的SYN请求,并指定了服务器的初始序列号(ISN)。

  3. 客户端发送ACK确认: 最后,客户端收到服务器的SYN-ACK响应后,会发送一个带有ACK标志位的数据包,表示确认了服务器的响应。这个ACK数据包中,客户端会确认收到了服务器的SYN响应,并指定了下一个要发送的序列号。

至此,三次握手完成,TCP连接建立成功,双方可以开始进行数据传输了。

前面给出的都是简图,更适合我们在面试过程中给出,因为更稳,要是画详图,画错了,那就得不偿失了。以下是三次握手的详图:

再通俗地解释一下三次握手的过程:

  1. 客户端向服务器发起建立连接的请求,发送一个SYN,此处的SYN就表示:我想跟你建立连接.
  2. 服务器大概率是会同意请求的(除非客户端太多了,负载极高,服务器无法响应),服务器收到SYN之后,会返回ACK(确认应答),表示收到!同时,服务器还会返回SYN,这个SYN的意思就是,我接受你的连接.
  3. 最后,客户端再给服务器返回一个ACK,表示:我也知道你同意我的请求了.

建立连接(三次握手)的意义

1)投石问路,确认当前通信路径是否畅通

例如地铁,每天早上会空车跑一趟,就是为了验证,这个路线是否畅通,是否存在一些问题。

因此,三次握手,对于可靠传输也是有意义的,但是相对于确认应答以及超时重传,起到的作用就稍逊一筹了。

2)验证通信双方,发送能力和接收能力是否正常

比如,张三和李四要开黑打游戏了。通常,在组队队伍的时候,双方都不知道自己的麦克风和听筒是否能正常工作,都先进行确认,这个过程其实就是三次握手,如下图:

上图中,张三扮演的就是客户端的角色,李四扮演服务器的角色。经过上述过程,张三和李四就够确认各自的麦克风和听筒都能正常工作了。此处,麦克风就对应发送能力,听筒就对应接收能力。

理解了上述图中的过程,我们就能清晰地理解,为什么是三次握手,而不是两次或四次握手:

  • 四次握手显然是可以的,但是没必要。
  • 如果是两次,一定是不行的。因为两次握手,李四(服务器)这边无法确认自己的发送能力是否正常,也无法确认张三(客户端)的接收能力是否正常。

3)三次握手的过程中,通信双方也会协商一些必要的参数

这些参数往往是以“选项”部分来体现的,前面说过,选项的范围是0~40字节。

其中有一个参数是很关键的,即TCP通信的序号:

  • 客户端在发送SYN报文时会包含一个随机生成的序列号(ISN),用于标识客户端发送数据的起始位置。
  • 服务器在回复ACK报文时会确认客户端的序列号,并生成自己的序列号(SSN),用于标识服务器发送数据的起始位置。

这样设计的原因,是为了避免出现一个情况,“前朝的剑,斩本朝的官”。具体过程如下:

  • 第一次连接的过程中,客户端传输的一个数据包,在路上堵车了,迟迟没有发送到对端。
  • 等到到了对端的时候,此时已经不是第一次连接了,而是新的连接了。
  • 此时,这份数据就应该被丢弃。
  • 由于,数据包是按照 IP + 端口号,来识别对端的。
  • 如果恰好出现,两次连接在同一台主机,都是同一个端口号的情况(这种情况是客户端的概率比较低,但服务器概率就比较大了),此时,再要处理这份数据就不合适了。

要解决这一问题,就是通过序号来区分当前数据是否是本次连接的数据。如果是,才进行处理,否则,就丢弃该数据。

二、断开连接(四次挥手)

连接,本质上就是让通信双方保存对方的信息。每个客户端/服务器,都要保存很多的对端信息。

信息一旦多了,就要用到数据结构。断开连接的本质目的,就是把对端的信息,从数据结构中删除/释放掉。

此处谈到的“四次挥手”,指的是谈恋爱中“和平分手”的这种情况。而单方面分手的情况,四次挥手不一定适用,这里会有其他方式来断开连接,因此,不意味着断开连接一定是四次挥手。

此处,又要介绍一个标志位,FIN,FIN => finish(结束)。即六位标志位中的第六位,用于请求关闭连接。

与三次握手不同的是,四次挥手,不一定非得是客户端先发FIN,服务器也可能先发FIN。

  • 调用socket.close(),会触发FIN
  • 进程直接结束,也会触发FIN

四次挥手的过程简图如下(客户端先发起关闭连接请求):

从上图可以看出,四次握手就是通信双方各自给对方发一个FIN,且各自给对方反馈一个ACK。

而且,这里的过程和刚开始的“四次握手”的过程非常相似。那四次挥手能否像三次握手一样,将中间的两次交互(ACK和FIN)合二为一呢?

  • 在标准的TCP四次挥手过程中,ACK和FIN通常是分开发送的。
  • 然而,在某些情况下,确实可能会发生ACK和FIN合并发送的情况,因为在理论上,ACK和FIN可以在同一数据包中发送。这种情况主要依赖于延迟应答和捎带应答机制(后面再说)。

如果实际通信过程中,ACK和第二个FIN时间间隔比较长,此时就无法进行合并了。以下是四次挥手的详图:

三、连接管理过程中涉及到的TCP状态转换

在前面三次握手和四次挥手的详图中,每进行一次握手或挥手,图中都有一个对应的状态。

TCP状态和之前多线程中谈到的“线程”状态,是类似的概念。TCP会根据收到的数据包以及协议规定的状态转换规则来更新连接状态:

  1. 分析收到的数据包: TCP协议栈会分析收到的数据包的头部信息,包括源端口、目标端口、标志位等,以确定数据包所处的状态以及下一步的操作。

  2. 执行状态转换规则: TCP协议定义了一系列状态转换规则,规定了在收到不同类型的数据包时应该如何更新连接状态。根据这些规则,TCP协议栈会根据收到的数据包来进行状态转换。

根据这些状态,TCP就能确定当前应该干什么,对于确保网络通信的可靠性和有效性至关重要。

这个图看起来非常复杂,实际上也真的很复杂,但是只需要关注几个比较重要的状态即可。 

先来看三次握手中比较重要的状态:

客户端还未发起SYN前,服务器处于LISTEN状态,表示服务器这边创建好 serverSocket 了,并且绑定端口号完成(手机开机了,信号良好,随时可以接听电话)

运行之前写的TCP回显服务器程序,通过命令行输入 netstat -ano | findstr 9090  这条命令(在这个命令中,netstat -ano 的作用是显示所有网络连接及其相关的进程ID(PID),而 findstr 9090 则是在输出包含端口号9090的所有进程),查看当前的状态:

ESTABLISHED 已确立的。表示客户端和服务器连接已经建立完毕(有人给我打电话,我接通了,此时我们就可以聊天了)

运行之前写的TCP回显客户端程序(可以运行多次),再次通过这个命令查看当前状态:

此处由于客户端和服务器在同一个机器上运行,因此客户端和服务器都会查出来。

再看四次挥手中比较重要的状态:

谁被动断开连接,谁进入 CLOSE_WAIT 状态。这个状态表示:

  • 接收方已被通知对方不再发送数据,但它仍然可以发送数据给对方。接收方需要执行应用层的关闭操作,并发送一个FIN包来关闭剩余的方向,即关闭对发起方的数据传输。 

CLOSE_WAIT 状态不太容易观察到,代码中会比较快速地关闭socket,这个时候,状态就已经从 CLOSE_WAIT -> LAST_ACK 了。但是如果服务器/客户端出现大量 CLOSE_WAIT  意味着代码可能出现bug了,比如忘记关闭 socket。

谁主动断开连接,谁进入 TIME_WAIT 状态:

  • 表示本端给对端发起FIN之后,对端也给我发FIN了,此时本端进入 TIME_WAIT 状态。这给最后一个ACK的重传留有一定的时间。

TIME_WAIT 状态在Windows上也不太容易观察。它存在的意义,主要是防止最后一个ACK丢失。具体的:

  • 在四次挥手的过程中,会涉及到确认应答和超时重传,如果没有收到ACK就视为丢包,此时就会重传FIN。
  • 进入TIME_WAIT 状态的这一方,如果在重传FIN这个环节,把TCP连接关闭了,保存的对端信息也随之释放了。此时意味着重传FIN的这一方就无法被返回ACK了。

此处 TIME_WAIT 也不是无休止的等待,通常等2MSL(MSL是TCP协议中的一个参数,表示数据段在网络中的最大存活时间,通常以秒为单位。MSL的值取决于具体的实现和环境,但通常为30秒到2分钟之间)

进入TIME_WAIT 状态的这一方等这么长时间,如果对方还没有重传,就说明不会再重传了。同时也确保了对方收到了最后的ACK确认。

至此,TCP协议的连接管理机制就介绍完了,并且前面还介绍了确认应答和超时重传机制,这三个机制都是保证TCP协议可靠传输的重要机制。连接管理机制总结如下:

三次握手(Three-way Handshake):

  1. 第一步(Client -> Server): 客户端发送一个带有SYN标志的数据包给服务器,表示请求建立连接,并选择一个初始序列号(ISN)。
  2. 第二步(Server -> Client): 服务器收到客户端的SYN包后,回复一个带有SYN和ACK标志的数据包给客户端,表示同意建立连接,并确认客户端的ISN,同时选择自己的ISN。
  3. 第三步(Client -> Server): 客户端收到服务器的确认后,再次发送一个带有ACK标志的数据包给服务器,确认服务器的ISN。此时,连接已建立,双方可以开始传输数据。

四次挥手(Four-way Handshake):

  1. 第一步(Client -> Server): 客户端发送一个带有FIN标志的数据包给服务器,表示不再发送数据,但仍可以接收数据。
  2. 第二步(Server -> Client): 服务器收到客户端的FIN包后,回复一个带有ACK标志的数据包给客户端,确认收到了关闭请求。
  3. 第三步(Server -> Client): 服务器发送一个带有FIN标志的数据包给客户端,表示服务器也不再发送数据,但仍可以接收数据。
  4. 第四步(Client -> Server): 客户端收到服务器的关闭请求后,回复一个带有ACK标志的数据包给服务器,确认收到了关闭请求。此时,连接终止。

通过三次握手,客户端和服务器建立起了可靠的连接;而通过四次挥手,双方安全地终止了连接,确保数据的可靠传输。

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

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

相关文章

Swift - 流程控制

文章目录 Swift - 流程控制if-else2. while3. for3.1 闭区间运算符3.2 半开区间运算符3.3 for - 区间运算符用在数组上3.3.1 单侧区间 3.4 区间类型3.5 带间隔的区间值 4. switch4.1 fallthrough4.2 switch注意点 5. 复合条件6. 区间匹配、元组匹配7. 值绑定8. where9. 标签语句…

DRF JWT认证进阶

JWT认证进阶 【0】准备工作 (1)模型准备 模型准备(继承django的auth_user表) from django.db import models from django.contrib.auth.models import AbstractUserclass UserInfo(AbstractUser):mobile models.CharField(ma…

c++ opencv

文章目录 错误1. C2039 "channels": 不是 "cv::DataType<_Tp>" 的成员2. 注意cv::mat的类型3. cv::mat求inv4. vector subscript out of range5. 使用determinant求行列式注意点 其他1.Vec3b的赋值与访问2. cv::mean3. 将cv::mat三通道改为单通道且保…

C语言——内存函数的实现与模拟

1. memcpy 函数 与strcpy 函数类似 1.头文件 <string.h> 2.基本格式 • 函数memcpy从source的位置开始向后复制num个 字节 的数据到destination指向的内存位置。 • 这个函数在遇到 \0 的时候并不会停下来。 • 如果source和destination有任何的重叠&#xff0…

2024年钉钉直播回放怎么下载

又到了2024年,最近钉钉迎来了一波更新,经过我的研究,总算研究出来了一个方法,并且做成了工具 首先&#xff0c;让我们了解一下钉钉直播回放的下载方法。 钉钉直播回放工具链接&#xff1a;https://pan.baidu.com/s/1oPWJOp8L2SBDlklt_t5WQQ?pwd1234 提取码&#xff1a;1234 -…

sml emacs 安装问题记录

sml & emacs 安装问题记录 可以直接用brew装&#xff0c;很方便 brew install --cask emacsbrew install smlnj --cask安装完smlng后测试sml命令 确认可以正常运行 如果找不到命令&#xff0c;需要配置环境变量 确认终端使用的是 zsh 还是 bash, 使用 echo $SHELL如果是zs…

Python Web开发框架详解:Django与Flask的比较与实践

Python Web开发框架详解&#xff1a;Django与Flask的比较与实践 在Python的Web开发领域&#xff0c;Django和Flask是两个非常受欢迎的框架。它们各自具有独特的特点和优势&#xff0c;适用于不同的开发场景。本文将对这两个框架进行详细的解释和比较&#xff0c;并给出一些实用…

【快速上手ESP32(基于ESP-IDFVSCode)】10-事件循环WiFi

事件循环 本来这篇文章是只写WiFi的&#xff0c;但是写的时候才发现离不开事件循环&#xff0c;因此再多添一点内容在WiFi前面。 事件循环简单来说就是一个&#xff08;循&#xff09;环&#xff0c;我们可以在这个环上绑上一些事件&#xff0c;我们也可以监听这个环&#xf…

JavaScript进阶(十五):JS 垃圾回收机制_vue gc

内存&#xff1a;由可读写单元组成&#xff0c;表示一片可操作空间&#xff1b;管理&#xff1a;人为的去操作一片空间的申请、使用和释放&#xff1b;内存管理&#xff1a;开发者主动申请空间、使用空间、释放空间&#xff1b;管理流程&#xff1a;申请-使用-释放&#xff1b;…

CodeTalker 踩坑实录

开源地址 GitHub - Doubiiu/CodeTalker: [CVPR 2023] CodeTalker: Speech-Driven 3D Facial Animation with Discrete Motion Prior 提供了预训练 运行报错 File "D:\Program Files\miniconda3\lib\site-packages\transformers\models\wav2vec2\modeling_wav2vec2.py&quo…

oracle sql monitor简单使用说明

一 sql monitor介绍 二 用命令行方式生成sql monitor报告 set long 1000000 set longchunksize 100000 set linesize 1000 set pagesize 0 set trim on set trimspool on set echo off set feedback off spool report_sql_monitor.html select dbms_sqltune.report_s…

线性代数-行列式-p1 矩阵的秩

目录 1.定义 2. 计算矩阵的秩 3. 矩阵的秩性质 1.定义 2. 计算矩阵的秩 3. 矩阵的秩性质

美国言语听力学会(ASHA)关于非处方 (OTC) 助听器的媒体声明(翻译稿)

美国国会于 2021 年 4 月 13 日批准美国听力学会积极提供建议&#xff0c;并一直积极参与制定FDA关于非处方助听器销售的拟议法规。根据2017年通过的立法授权。学院积极参与帮助塑造授权立法&#xff0c;并就即将出台的条例分享了建议。 根据美国卫生与公众服务部NIH / NIDCD的…

用Python绘制了几张有趣的可视化图表

流程图存在于我们生活的方方面面&#xff0c;对于我们追踪项目的进展&#xff0c;做出各种事情的决策都有着巨大的帮助&#xff0c;而对于的Python而言呢&#xff0c;绘制流程图也是十分轻松的&#xff0c;今天小编就来为大家介绍两个用于绘制流程图的模块&#xff0c;我们先来…

基于Web的停车场管理系统设计与实现:技术总结与展望

引言 随着社会经济的快速发展&#xff0c;汽车保有量的激增使得停车难问题日益凸显。为了有效解决这一问题&#xff0c;本人在导师的指导下&#xff0c;设计并实现了一套基于Web的停车场管理系统。本文将从技术角度出发&#xff0c;详细总结本系统的设计思路、技术细节以及实现…

12 JavaScript学习: 字符串

JavaScript 字符串 JavaScript 字符串是一种用于存储和操作文本数据的数据类型。字符串可以包含字母、数字、符号和空格等字符。在 JavaScript 中&#xff0c;字符串可以使用单引号&#xff08;&#xff09;或双引号&#xff08;"&#xff09;来定义。 例如&#xff1a;…

链表与模拟LinkedList的实现

1. ArrayList的缺陷 ArrayList底层使用数组来存储元素 由于其底层是一段连续空间&#xff0c;当在ArrayList任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后 搬移&#xff0c;时间复杂度为O(n)&#xff0c;效率比较低。因此ArrayList不适合做任意位…

机械臂过程

rosdep install --from-paths src --ignore-src --rosdistro melodic0、安装机械手臂 官方教程&#xff1a; 前人教程&#xff1a;UR5机械臂仿真实例 rosdep update 出错&#xff0c;使用小鱼的大佬的 一键配置 wget http://fishros.com/install -O fishros && . fish…

多快好省 | 餐饮零售业敏感数据保护建设思路

01 背景&场景 谈及“大数据”&#xff0c;很多人首先想到的是各类社交媒体、电信通讯商等大型技术企业&#xff0c;作为涉及用户个人信息的餐饮与零售业往往被忽视。不论是线上外卖平台、线下连锁餐饮行业&#xff0c;还是连锁商超、新零售等行业&#xff0c;在全面线上化、…

JS设置Ajax为同步或异步

在使用 AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;时&#xff0c;可以通过设置 XMLHttpRequest 对象的 async 属性来控制请求是同步&#xff08;synchronous&#xff09;还是异步&#xff08;asynchronous&#xff09;。 异步&#xff08;Asynchronous&…