传输层协议 —— 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.rhkb.cn/news/430100.html

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

相关文章

远程升级频频失败?你可能忽略了模组差分包…

去年开发的一个项目产品,用的是合宙4G-Cat.1低功耗模块Air780E。 最近有客户反馈在乡村里频繁出现掉线的情况。通过换货、换SIM卡对比排查测试,发现只有去年5月22号采购的那批模块在客户环境附近会出现掉线的情况,而今年4月份采购的模块批次…

【Go】Go 环境下载与安装教程(Windows系统)

引言 Go,也被称为Golang,是一种静态类型,编译型的编程语言,由Google设计和开发。Go语言的设计目标是“解决软件开发中的一些问题”,特别是在大规模软件系统的构建和维护方面。 下载安装包 打开官网下载页面&#xff…

03 添加并发请求

03 添加并发请求 我们通过两种方式演示发起多个请求: 使用 async 和 await 方式使用 Promise.all() 方式 首先使用async 和 await 方式发送请求,使用 async 和 await 能够控制异步任务以同步的流程执行,代码如下,这时候就会产生…

Git 提交规范

一、Git 提交规范的基本格式 通常&#xff0c;Git 提交信息采用以下格式&#xff1a; <type>: <subject><body><footer>type&#xff08;提交类型&#xff09;&#xff1a;用于说明提交的性质&#xff0c;常见的类型有以下几种&#xff1a; feat&…

仓颉编程语言4,遇到BUG求助

本来准备整仓颉链接Mysql数据库。参考&#xff1a;GitCode - 全球开发者的开源社区,开源代码托管平台 这种方式是拿mysql官方的dll&#xff0c;编译一下&#xff0c;然后再封装成仓颉数据库驱动。这种方式不够逼格&#xff0c;所以准备解析mysql网络协议&#xff0c;从0开始写…

cmd快速进入文件夹目录下

首先&#xff0c;将文件夹直接点击左键拖动至cmd窗口中&#xff0c;就可以得到目录路径。 还有就是&#xff0c;在命令行直接敲入D:或者C:就可以在磁盘之间进行转换&#xff0c;注意冒号不要丢。 再有&#xff0c;如果进入某磁盘中的一个文件夹&#xff0c;使用cd命令。路径获取…

SpringBoot实战(三十)发送HTTP/HTTPS请求的五种实现方式【下篇】(Okhttp3、RestTemplate、Hutool)

目录 一、五种实现方式对比结果二、Demo接口地址实现方式三、Okhttp3 库实现3.1 简介3.2 Maven依赖3.3 配置文件3.4 配置类3.5 工具类3.6 示例代码3.7 执行结果实现方式四、Spring 的 RestTemplate 实现4.1 简介4.2 Maven依赖4.3 配置文件4.4 配置类4.5 HttpClient 和 RestTemp…

Parallels Desktop 20 for Mac 推出:完美兼容 macOS Sequoia 与 Win11 24H2

Parallels Desktop 20 for Mac 近日正式发布&#xff0c;这一新版本不仅全面支持 macOS Sequoia 和 Windows 11 24H2&#xff0c;还在企业版中引入了一个全新的管理门户。新版本针对 Windows、macOS 和 Linux 虚拟机进行了多项改进&#xff0c;其中最引人注目的当属 Parallels …

导出导入Oracle数据库使用黑框命令方式exp、imp【亲测】

下载工具 根据自己数据库的版本下载&#xff0c;以v19为例&#xff1a; 下载基础包Basic Package和工具包Tools Package 两个压缩包中的文件夹一样&#xff0c;但内容不一样&#xff0c;将两个压缩包中的文件解压合并到一起 https://www.oracle.com/database/technologies/inst…

SpringCloud入门(六)Nacos注册中心(下)

一、Nacos环境隔离 Nacos提供了namespace来实现环境隔离功能。 nacos中可以有多个namespace。namespace下可以有group、service等。不同namespace之间相互隔离&#xff0c;例如不同namespace的服务互相不可见。 使用Nacos Namespace 环境隔离 步骤&#xff1a; 1.在Nacos控制…

时间序列无监督异常点检测算法_孤立森林,局部离群因子检测和自编码器

数据入口&#xff1a;压气机异常检测一维时间序列 - Heywhale.com 该数据为采样自工业压气机的一维时间序列数据。本文将通过无监督时间序列算法进行时间序列异常检测。针对时间序列数据&#xff0c;常用的无监督异常检测算法包括&#xff1a;孤立森林&#xff08;Isolation Fo…

【Yonghong星球】Windows平台上Yonghong的Python、DM-Engine安装与配置详细攻略

文章目录 问题描述问题解决(配置相应的python计算服务)拓展 第三方工具包安装/更新其他出现问题 问题描述 当我们进行深度分析的时候&#xff0c;运行结点报错&#xff0c;这是因为需要配置相应的python计算服务。 报错内容&#xff1a; 2024-09-20 13:57:22 开始运行“各省G…

js中的 赋值 浅拷贝 和 深拷贝 详细解读

js数据类型主要分基本数据类型和引用数据类型。前者包括Number,String等&#xff0c;后者主要是Object,因此以下会针对不同的数据类型来分析,需要的朋友可以参考一下 基本数据类型&#xff08;Primary Data Types&#xff09;: String&#xff08;字符串&#xff09; Number&…

三端全隔离485中继器光电隔离工业级 RS485集线器2口信号放大器 抗干扰防雷

485中继器光电隔离工业级 RS485集线器2口信号放大器 抗干扰防雷https://item.taobao.com/item.htm?ftt&id713033449656 哪里信号不好&#xff0c;中继器就接哪里 将有效的对信号进行隔离放大 信号隔离 电源隔离 双向传输 即插即用 增强抗干扰 延长通信距离 产品概…

防火墙详解(二)通过网页登录配置华为eNSP中USG6000V1防火墙

配置步骤 步骤一 打开eNSP&#xff0c;建立如下拓扑。防火墙使用&#xff1a;USG6000V1。 Cloud的作用是通过它可以连接本地的网卡&#xff0c;然后与我们的电脑进行通信。 由于防火墙USG6000V&#xff0c;不能直接开启&#xff0c;需要的导入包&#xff0c;所以需要在华为官网…

爬虫过程 | 蜘蛛程序爬取数据流程(初学者适用)

蜘蛛程序&#xff08;也称网络爬虫&#xff0c;是搜索引擎的重要组成部分&#xff09; 主要功能&#xff1a;遍历互联网&#xff0c;抓取网站信息并建立索引&#xff0c;便于用户在搜索引擎中检索到最新的网页内容工作原理&#xff1a;从初始网站页面的URL开始&#xff0c;发送…

【人工智能】看我如何用4个AI大模型,实现了堪比o1-preview的思维链。内含3个AI问答的数据比对结果!

在当今人工智能的快速发展中&#xff0c;如何高效地利用不同的AI模型来提升工作效率&#xff0c;成为了许多开发者和企业关注的焦点。本文将深入探讨如何通过4个GPT-4o模型与其他多模型的编排&#xff0c;构建一个强大的AI工作流&#xff0c;并与o1-preview的数据结果进行对比&…

怎么录屏?免费录屏软件推荐,电脑屏幕与摄像头内容录制与分享指南

在数字化办公和在线教育日益普及的今天&#xff0c;录屏软件成为了我们不可或缺的工具。无论是制作教学视频、游戏直播&#xff0c;还是远程会议记录&#xff0c;一个好的录屏软件都能让这些任务变得轻而易举。但面对市场上琳琅满目的录屏软件&#xff0c;我们该如何选择呢&…

国内短剧cps系统和短剧(播放)系统的区别,附各源码部署教程

国内短剧项目主要分为两大形式&#xff1a;一种是做短剧播放平台&#xff0c;让用户付费观看&#xff1b;另一种是做短剧的分销&#xff0c;就是将他人的平台短剧推广&#xff0c;可做平台可入驻&#xff0c;拿分成。 首先来说一下短剧播放平台&#xff08;短剧系统&#xff0…

【推荐100个unity插件之26】Unity 地形Terrain的绘制和使用进阶内容 —— Terrain Tools和 Terrain Toolbox的使用

文章目录 前言一、Terrain Toolbox的使用安装Terrain Tools下载导入资产样本打开选择Terrain Toolbox创建地形切割地形创建不同分组的地形terrain group设置第一个pixel error是LOD精度&#xff0c;值越小精度越高&#xff0c;当然性能开销也就越大第二个base map distance是指…