传输层协议 —— TCP协议(上篇)

目录

1.认识TCP

2.TCP协议段格式

3.可靠性保证的机制

确认应答机制

超时重传机制

连接管理机制

三次握手

四次挥手


1.认识TCP

在网络通信模型中,传输层有两个经典的协议,分别是UDP协议和TCP协议。其中TCP协议全称为传输控制协议(Transmission Control Protocol),从名称就可以看出,TCP协议需要对数据的传输进行严格的控制。

UDP协议具有无连接、不可靠、面向数据报的特点,而TCP协议恰恰相反,具有 有连接、可靠、面向字节流的特点。而其中,可靠性是TCP最著名的特点;也正因为TCP协议需要保证通信的可靠性,所以TCP协议才会有一系列保证可靠性的机制和策略,这也是我们需要重点学习的内容。

2.TCP协议段格式

所谓协议,其实就是通信双方都认识的结构化的数据。TCP协议是传输层的协议,传输层的协议是在操作系统内部实现的,所以操作系统内部一定有TCP协议相关的代码。

Linux内核中TCP协议部分代码:

把代码形象化便得到了下面这张图:

  

各个字段的粗略认识:

1、16位源端口和16位目的端口:表明数据从哪个进程来,要发送给哪个进程。

2、32位序号和32位确认序号:序号可以用来对接收到的报文进行按序到达去重,确认序号表明该序号之前的报文都收到了。(后面会详谈)

3、4位首部长度:表明TCP报头的长度。TCP报头由固定长度的20字节和不固定的选项构成,四位首部长度表明了这两部分共同的长度。其中,首部长度是有基本单位的,基本单位是4字节。4个比特位的最大取值是15,所以四位首部长度的最大范围是60字节。

4、6位标记位:

URG: 表明紧急指针是否有效

ACK: 表明确认号是否有效

PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走

RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段

SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段

FIN: 通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段

5、16 位窗口大小: 表明自己的接收能力,通信双方可以动态的调整发送报文的大小。

6、16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分.

7、16 位紧急指针: 标识哪部分数据是紧急数据,需要优先处理。

8、40 字节头部选项: 暂时忽略;

3.可靠性保证的机制

确认应答机制

铺垫:什么是序列号?

我们可以这样理解。操作系统会为TCP分配两个进行通信的缓冲区,我们把缓冲区当成char类型的大数组,那么缓冲区中的数据不就天然的具有编号了吗?这个编号我们把它叫做序列号。序列号是对每个字节的编号,这也体现出了TCP面向字节流的特点。

TCP需要保证可靠性,首先需要保证发送方发送的数据,接收方要能收到。那发送方如何得知接收方是否收到了自己发送的数据呢?这个时候,TCP协议便引入了确认应答机制。

确认应答机制就是接收方对接收到的报文进行应答,这样一来,发送方就知道对方有没有收到我发送的数据了。并且这个应答是需要在指定的时间内收到的,如果主动发送数据的一方没有在规定时间内收到应答,那么它就会认为对方没有收到我发送的数据。

但是问题又来了,发送方发送一次消息,接收方应答一下,这样似乎没有什么问题,但是,这种通信模式的效率是非常低的,所以,通信双方进行通信的时候,数据的发送往往是并行的。

那么问题又来了,接收方收到多个报文的时候,如何保证能够正确的进行应答呢? 其实啊,应答的时候,是通过序列号来完成的。序列号是能够确认顺序的,接收方会对收到的报文根据序列号进行排序,一旦排好序之后,接收方就会先判断最小序列号之前的报文是否全部收到,如果该序列号之前的报文全部收到,才会进行应答,并且应答的时候是需要填充32位确认序号的,确认序号的值是收到的报文的序列号+1,表明该序列号之前的数据我全部收到了,下次你应该从哪里发。这其实这就是按序到达策略。

如果收到了对方的确认序号,下一次发送数据的序号就是 收到的确认序号+要发送报文的长度。 

我们已经知道了确认应答机制是通过序列号来完成的,那你有没有这样的疑问,为什么报头中有序列号了,还需要有一个确认序号呢?直接用序列号的字段来表明确认序号不就可以了吗?

这是因为,在实际通信的过程中,接收方往往也需要向发送方响应消息。 也就是说数据的接收方既要响应,又要发送消息;那么这个过程可不可以一步到位呢?这是可以的,序列号表明自己发送的报文,确认序号可以作为接收消息的响应。那么,这样一来,中间的两次发送可以合并为一次发送,这样,不就又提高了通信的效率了吗?这其实就是捎带应答

超时重传机制

前面我们已经知道了TCP可靠性保证的一个机制 —— 确认应答机制,接收方需要向发送方进行响应,表明自己收到了对方的消息。但是,如果发送方一直没有收到对方的响应,会怎么办呢?这就需要引入超时重传机制了。

发送方发送数据之后,会等待一段时间,在该时间内,如果收到了对方的响应,就表明对方收到了我发送的数据;如果在该时间段内,没有收到对方的应答,发送方就会认为对方没有收到自己发送的数据,这个时候就需要再发送一遍,这就是超时重传机制。

超时重传的时间怎么定呢?

数据是需要通过网络进行发送的,如果网络状态比较好的话,数据发送的速度就会比较快,如果网络比较差的话,数据发送的速度就会比较慢。也就是说,网络的状态是动态变化的,那么超时时间的设置也必须是动态变化的,如果网络状态比较好的话,超时时间就可以设置的短一点,如果网络状态比较差的话,超时时间就设置的长一点。

• Linux 中, 超时时间以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是500ms 的整数倍.
• 如果重发一次之后, 仍然得不到应答, 等待 2 * 500ms 后再进行重传.
• 如果仍然得不到应答, 等待 4 * 500ms 进行重传. 依次类推, 以指数形式递增.
• 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接.

超时重传机制存在的问题

由于超时重传机制的存在,在规定时间内没有收到应答就会进行重传。那有没有可能,发送方发送的数据在网络中阻塞了一段时间,但是在一段时间后被对方收到,但是这个时候已经重传了?还有没有可能,对方已经收到了报文,但是响应丢了呢?不管是那种情况,都会导致,发送方重复发送对方已经收到的报文,那么接收方就会收到重复的报文,这个时候怎么办呢?

不要忘了TCP协议报头中有序列号,序列号不仅仅可以用来做为应答,还可以用来去重。当接收方接收到消息的时候,它会根据序列号判断这个报文我曾经是否收到过,如果收到过的话,就直接将该报文丢弃了。所以我们不用担心重复报文的问题。

接收方如何判断这个报文我曾经是否收到过呢?

这个问题更具体的解决策略就是,接收方根据自己最新一次的确认序号就能知道多少号报文之前的报文我都收到了,如果对方发过来的报文的序号小于最新一次的确认序号,那么该报文就能丢弃了,也就实现了去重。

连接管理机制

TCP协议是面向连接的协议,通信之前,通信双方必须进行三次握手建立连接,通信之后,通信双方必须进行四次挥手断开连接。

三次握手

使用TCP协议进行通信的时候,通信双方必须建立连接才能进行正常的通信,当通信结束时,通信双方也必须断开连接以确保不会造成服务器端的资源浪费。所以在基于TCP通信的过程中,会有各种各样的报文,有的报文是用来请求建立连接的,有的报文是用来进行正常通信的,有的报文是用来请求断开连接的。为了区分这些不同的报文,于是,TCP协议报头中引入了标记位

TCP协议中与连接管理有关的标记位:

SYN:SYN标记位也称为同步标记位。如果客户端发送的报文中的SYN标记位被置为1,服务器端就知道对方想与我建立连接了。

FIN:FIN标记位也称为结束标记位。如果客户端发送的报文中的FIN标记位被置为1,服务器端就知道对方想与我断开连接了。

ACK:ACK标记位我们可以称其为应答标记位。用于表明该应答中的确认序号是否有效,也就是表明该报文是否是用于应答的报文。

RST:重置标记位。要求对方重新建立连接。

三次握手过程中套接字的状态变化: 

1.双方未建立连接的时候,双方的套接字都处于CLOSED状态。

2.服务器端需要先调用listen接口将自己的套接字状态设为LISTEN状态,等待客户端连接。

3.此时,客户端需要主动调用connect接口向服务器发起连接,此时客户端套接字状态变为SYN_SENT状态。

4.当服务器端监听到连接请求(SYN报文), 就将该连接放入内核等待队列中, 如果它也想与对方建立连接,就会在发送的报文中将SYN和ACK标记位置1,当该报文发送出去的时候,客户端的套接字状态进入SYN_RCVD状态。

5.当客户端收到服务器端的应答的时候,他就认为连接建立好了,客户端的套接字状态进入ESTABLISHED状态,并向服务器端发送一个ACK报文,表明我也愿意与你通信。

6.当服务器端收到这个ACK报文的时候,服务器端也认为连接建立好了,服务器端的套接字状态就进入ESTABLISHED状态。

此时,通信双方都认为连接建立好了;在这个过程中,客户端通过connect函数发起连接,服务器端的accept函数并不参与三次握手。

一个问题:

在这个过程中,我们发现,客户端认为连接建立好的时间是早于服务器端的。如果客户端发送信息的需求非常迫切,一旦认为连接建立好了就要发送消息,但是此时服务器端的连接还没有建立好呢?

这个时候,当服务器端收到客户端的正常的通信报文的时候,就会向客户端响应一个RST标记位被置为1的报文,要求对方重新建立连接。也就是重新进行三次握手。

那你有没有思考过一个问题,为什么建立连接之前要进行三次握手呢?

1.双方要进行通信,首先要确保通信的信道是健康的。三次握手的工程中,客户端发送的数据,被服务器端接收到之后,服务器端要对客户端进行响应,如果客户端也收到了服务器端的应答,说明客户端是能够进行收发的;同理,客户端也要对服务器端进行响应,如果服务器端收到了客户端的应答,说明服务器端也是能够进行收发的。

2.通信双方都能进行数据的收发还不够,还需要检查对方是否愿意和自己通信。三次握手的过程中,都有一次给对方的响应,说明对方是愿意和自己进行通信的。

此时,通信双方都能够进行数据的收发,并且,对方也愿意与自己进行通信,那么此时就可以建立连接进行通信了。

三次握手的本质:

在三次握手的过程中,服务器是提供服务的一方,当有客户来请求建立连接的时候,服务器肯定是愿意的,并且也要询问对方是否愿意和自己建立连接,再者,两次报文中并不涉及数据,只是涉及报头中标记位的变化,所以,两次报文可以进行捎带应答,合并成一个报文,这才有了三次握手。也就是说,三次握手的本质也是四次握手,只不过中间的两次被捎带应答,合二为一了。

谈完三次握手建立连接,我们现在谈谈四次挥手断开连接。

四次挥手

四次挥手过程中套接字状态的变化:

我们假如客户端主动请求断开连接。

1.客户端主动调用 close 时, 向服务器发送结束报文段, 同时进入 FIN_WAIT_1;

2.当客户端主动关闭连接(调用 close), 服务器会收到结束报文段, 服务器返回确认报文段并进入 CLOSE_WAIT;

3. 客户端收到服务器对结束报文段的确认, 则进入 FIN_WAIT_2, 开始等待服务器的结束报文段;

4.服务器进入 CLOSE_WAIT 后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用 close 关闭连接时, 会向客户端发送FIN, 此时服务器进入 LAST_ACK 状态, 等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN)

5.客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出 ACK;客户端要等待一个 2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED 状态.

6.服务器收到了对 FIN 的 ACK, 彻底关闭连接

理解CLOSE_WAIT状态和TIME_WAIT状态:

当客户端主动请求断开连接的时候,说明客户端要发送的数据发送完了,但是服务器端要发送的数据不一定发送完了,所以服务器端不能立即调用close函数断开连接,而是进入CLOSE_WAIT状态,直到将要发送的数据发送完之后,才向客户端发送请求断开连接的报文,也就是说进入CLOSE_WAIT状态的一方不会立即关闭文件描述符。所以,如果我们发现我们的服务器上有大量的CLOSE_WAIT状态,很有可能是服务器端没有关闭文件描述符。

如果客户端是主动断开连接的一方,当客户端收到来自服务器端的断开连接的请求报文的时候,就会进入TIME_WAIT状态,处于TIME_WAIT状态的一方不会立即断开连接,而是需要进行一段时间的等待。这是因为网络中可能还有历史报文,如果连接关闭之后,立马又来了相同的连接,那么历史报文就会对新的连接发送的报文造成影响,等待一段时间可以让历史报文消散。当然,还有一个原因。如果服务器端没有收到客户端发送的最后一个ACK报文,服务器端可以要求客户端进行超时重传,此时连接还在,是可以进行超时重传的,也就保证最后一个报文可靠到达。

进入TIME_WAIT状态的一方需要等待的时长是两个MSL(maximum segment lifetime)时间,MSL时间并不是指数据从发送到接收所花费的时间,而是数据在网络中的最大存活时间。

等待两个MSL时间,是因为客户端发送最后一个ACK需要消耗一个MSL时间,如果服务器端要求客户端进行重传,客户端接收消息也需要消耗一个ACK时间。

和三次握手一样,我们来思考一下,为什么断开连接要进行四次挥手呢?

和三次握手一样,断开连接也需要表明通信双方的意愿,这个过程需要双方进行至少一次的互问互答来完成,当双方都发起断开连接的请求之后,并且也都收到了对方肯定的回答,那么这个时候就可以断开连接了。

四次挥手的过程和三次握手的过程挺像的,那中间的两个报文能否合并成一个报文呢?

通信双方断开连接的时候,必须保证待发送的数据都已经发送完了。假如客户端发起断开连接的请求,客户端是知道自己没有数据再要发送了,也就不会再向服务器发送消息了(这里的消息主要是数据,不包括协议报头),所以才会要求断开连接。但是服务器端不一定将待发送的数据都发送完了,服务器必须保证待发送的数据发送完之后才能断开连接。也就是说客户端发起断开连接请求的时候,如果服务器没有需要发送的数据了,那么此时是可以将中间的两个报文合二为一的,但是这种情况的概率非常小。所以断开连接的时候通常是四次挥手。

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

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

相关文章

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0920)

十三、文章分类页面 - [element-plus 表格] Git仓库:https://gitee.com/msyycn/vue3-hei-ma.git 基本架子 - PageContainer 功能需求说明: 基本架子-PageContainer封装文章分类渲染 & loading处理文章分类添加编辑[element-plus弹层]文章分类删除…

pg入门3—详解tablespaces—下

pg默认的tablespace的location为空,那么如果表设置了默认的tablespace,数据实际上是存哪个目录的呢? 在 PostgreSQL 中,如果你创建了一个表并且没有显式指定表空间(tablespace),或者表空间的 location 为…

OpenCV运动分析和目标跟踪(4)创建汉宁窗函数createHanningWindow()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 此函数计算二维的汉宁窗系数。 createHanningWindow是OpenCV中的一个函数,用于创建汉宁窗(Hann window)。汉宁…

肾癌的多模态预测模型-临床-组织学-基因组

目录 摘要 技术路线 ① lncRNA的预测模型 ②病理 WSI 的分类器 ③临床病理分类器 模型结果 与别的模型比较 同行评审学习 1)使用lncRNA的原因 2)模型临床使用意义 3)关于截止值的使用 摘要 A multi-classifier system integrated…

STC89C52定时器与中断 详细介绍 0基础入门

STC89C52定时器与中断 前言定时器/计数器定时器/计数器 功能选择定时器/计数器 模式选择使用寄存器进行功能选择与模式选择 中断使用寄存器进行中断配置中断执行操作 总结完整程序 前言 对于定时器与中断,这是两个完全不同的概念,在单片机中它们也对应着…

【HTTP】认识 URL 和 URL encode

文章目录 认识 URLURL 基本格式**带层次的文件路径****查询字符串****片段标识符** URL encode 认识 URL 计算机中非常重要的概念,并不仅仅是在 HTTP 中使用。用来描述一个网络资源所处的位置,全称“唯一资源定位符” URI 是“唯一资源标识符“严格的说…

mac命令行分卷压缩与合并

对当前目录内的文件压缩的同时分卷 //语法:zip -r -s 1m 压缩文件名.zip 当前路径 zip -r -s 1m split.zip . //解压 zip -s 0 split.zip --out unsplit.zip unzip unsplit.zip 将一个zip文件进行分卷 一个900k的压缩包名为hello.zip,将其分割为每500K一个zip zip - hello.…

Microsoft Edge 五个好用的插件

🐣个人主页 可惜已不在 🐤这篇在这个专栏 插件_可惜已不在的博客-CSDN博客 🐥有用的话就留下一个三连吧😼 目录 Microsoft Edge 一.安装游览器 ​编辑 二.找到插件商店 1.打开游览器后,点击右上角的设置&#…

第十四章:html和css做一个心在跳动,为你而动的表白动画

💖 让心跳加速,传递爱意 💖 在这个特别的时刻,让爱在跳动中绽放!🌟 无论是初次相遇的心动,还是陪伴多年的默契,我们的心总在为彼此跳动。就像这颗炙热的爱心,随着每一次的跳动,传递着满满的温暖与期待。 在这个浪漫的季节,让我们一同感受爱的律动!无论你是在…

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-19

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-19 1. SAM4MLLM: Enhance Multi-Modal Large Language Model for Referring Expression Segmentation Authors: Yi-Chia Chen, Wei-Hua Li, Cheng Sun, Yu-Chiang Frank Wang, Chu-Song Chen SAM4MLLM: 增强多模…

防火墙详解(三)华为防火墙基础安全策略配置(命令行配置)

实验要求 根据实验要求配置防火墙: 合理部署防火墙安全策略以及安全区域实现内网用户可以访问外网用户,反之不能访问内网用户和外网用户均可以访问公司服务器 实验配置 步骤一:配置各个终端、防火墙端口IP地址 终端以服务器为例&#xff…

离散制造 vs 流程制造:锚定精准制造未来,从装配线到化学反应,实时数据集成在制造业案例中的多维应用

使用 TapData,化繁为简,摆脱手动搭建、维护数据管道的诸多烦扰,轻量替代 OGG, Kettle 等同步工具,以及基于 Kafka 的 ETL 解决方案,「CDC 流处理 数据集成」组合拳,加速仓内数据流转,帮助企业…

Android IME输入法启动显示隐藏流程梳理

阅读Android AOSP 12版本代码,对输入法IME整体框架模块进行学习梳理,内容包含输入法框架三部分IMM、IMMS、IMS的启动流程、点击弹出流程、显示/隐藏流程,以及常见问题和调试技巧。 1. IME整体框架​​​​​​​ IME整体分为三个部分&#xf…

股指期货的持仓量指标如何分析?有哪些作用?

股指期货市的持仓量是一个极其重要的指标,它就像市场的“晴雨表”,能反映出投资者的信心、市场的热度以及潜在的趋势。下面,我们就用大白话的方式来详细解读一下股指期货持仓量指标的分析方法及其作用。 一、什么是股指期货持仓量&#xff1…

用CPU训练机器学习模型

人工智能最近的成功通常归功于 GPU 的出现和发展。GPU 的架构通常包括数千个多处理器、高速内存、专用张量核心等,特别适合满足人工智能/机器学习工作负载的密集需求。 不幸的是,人工智能开发的快速增长导致对 GPU 的需求激增,使得 GPU 难以…

ESP32/ESP8266开发板单向一对多ESP-NOW无线通信

目录 简介读取ESP32/ESP8266接收方Receiver的MAC地址ESP32发送方Sender程序ESP32/ESP8266接收方Receiver程序ESP-NOW通信验证总结 简介 本实验通过ESP-NOW无线通信协议实现ESP32开发板向多个ESP32/ESP 8266开发板发送数据。 读取ESP32/ESP8266接收方Receiver的MAC地址 读取…

Nginx反向代理出现502 Bad Gateway问题的解决方案

🎉 前言 前一阵子写了一篇“关于解决调用百度翻译API问题”的博客,近日在调用其他API时又遇到一些棘手的问题,于是写下这篇博客作为记录。 🎉 问题描述 在代理的遇到过很多错误码,其中出现频率最高的就是502&#x…

LabVIEW提高开发效率技巧----代码规范与文档记录

良好的代码规范与文档记录在LabVIEW开发中至关重要。它不仅能够大幅提升开发效率,还为后续的维护和项目交接提供便利。下面将从命名规则、注释标准、功能说明等多个角度,介绍如何通过规范化开发提高项目的可维护性与协作性。 1. 保持一致的命名规则 在L…

Flutter局域网广播(UDP通信)与TCP通信

前言 现在有一个需求,手机和ESP32通过WIFI进行通信。流程如下: 手机创建TCP服务器手机向192.168.0.255的1002端口广播自己的ip地址以及TCP服务器的端口号ESP32监听到1002的广播内容后,连接手机的TCP服务器。最后就是ESP32硬件和TCP服务器进…

双击热备 Electron网页客户端

安装流程: 1.下载node.js安装包进行安装 2.点击Next; 3.勾选,点击Next; 4.选择安装目录 5.选择Online 模式 6.下一步执行安装 。 7.运行cmd,执行命令 path 和 node --version,查看配置路径和版本 8.Goland安装插件node.js 9.配置运行…