【网络原理】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语言——内存函数的实现与模拟

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 -…

【快速上手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;…

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;我们先来…

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…

Rest微服务案例

Rest 父工程构建microservicecloud-api公共子模块Modulemicroservicecloud-provider-dept-8001部门微服务提供者Modulemicroservicecloud-consumer-dept-80部门微服务消费者Module 以Dept部门模块做一个微服务通用案例 Consumer消费者&#xff08;Client&#xff09;通过REST调…

ssm082基于java斗车交易系统设计与实现+vue

斗车交易系统 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&…

第三篇:Python编程基础:掌握核心语法与开发技巧

Python编程基础&#xff1a;掌握核心语法与开发技巧 1 引言 在这个信息化迅速蔓延的世界中&#xff0c;Python语言如同钥匙一般开启了通往各种可能性的大门。无论你是数据科学家、网络工程师、机器学习专家&#xff0c;还是仅仅对自动化办公感兴趣的办公室人员&#xff0c;Pyt…

环境配置——Windows平台配置VScode运行环境为远程服务器或虚拟机

1. 远程机需要先安装SSH服务&#xff0c;命令如下 sudo apt install openssh-server 2. 安装好后需要开启SSH服务&#xff1a; sudo service sshd start 3. 查看SSH服务是否有被开启&#xff1a; sudo systemctl status sshd.service 4. 本地Windows需要生成密钥将公钥放…

CTFshow-PWN-栈溢出(pwn36)

存在后门函数&#xff0c;如何利用&#xff1f; 好好好&#xff0c;终于到了这种有后门函数的了 checksec 检查一下&#xff1a; 32 位程序&#xff0c;RELRO 保护部分开启 RWX: Has RWX segments 存在可读可写可执行的段 使用 ida32 看 main 函数 跟进 ctfshow 函数…

go语言并发实战——日志收集系统(十) 重构tailfile模块实现同时监控多个日志文件

前言 在上一篇文章中&#xff0c;我们实现了通过etcd来同时指定多个不同的有关分区与日志文件的路径&#xff0c;但是锁着一次读取配置的增多&#xff0c;不可避免的出现了一个问题&#xff1a;我们如何来监控多个日志文件&#xff0c;这样原来的tailFile模块相对于当下场景就…

Golang | Leetcode Golang题解之第46题全排列

题目&#xff1a; 题解&#xff1a; func permute(nums []int) [][]int {var (n len(nums)dfs func(vals []int) // 已选择数 排列为vals 后续回溯继续选择 直至选完ans [][]int)dfs func(vals []int) {//边界if len(vals) n {ans append(ans, vals)}//转移 枚举选哪个f…