【计算机网络】TCP报文详解

认识TCP报头

其实协议的形式都是一个结构化的数据,TCP协议也不例外。一起来看看TCP协议的报头是怎么样的。

在这里插入图片描述

以上就是TCP报头,实际上是一个结构化的数据,也就是一个结构体。例如:

struct tcp_hdr
{unsigned int stc_port : 16;unsigned int desc_port : 16; unsigned int seq;unsigned int ack_seq;....
};

目的端口号&&源端口号

其中16位源端口号,就是你当前发送报文的端口号。目的端口号则是目标主机的端口号。

这也就是我们在用accept时,能够获取连接套接字的同时,还能获取到对端主机的端口号(ip也获取到了,这个在网络层的时候解释)。 而目的端口号也很好理解,因为端口号能够确定一台主机中唯一的一个进程。当你的报文被发送到对端主机的时候,就能够通过端口号去锁定对应的PCB进程。

4位首部长度

4位首部长度代表的是报头占多少大小,这回有人问了,4位不是 0000 - 1111 ,也就是 0 -15这个区间吗?

可是报头的基本大小都20了。 实际上上,4位首部长度 * 4 才等于报头的实际大小。也就 0 - 60区间,报文长度默认是20字节,也就说明4位首部长度默认为5。

如何解包&&分用?

如何解包

还记得我们上面提到的4位首部长度吗? 当TCP层收到TCP报文时,会先提取前20个字节。获得除了选项以外,报文的其他信息。随后再去查看4位首部长度,如果4位首部长度 * 4 大于20 。那么再减去20个字节,把剩余的字节提取出来,那么剩下的不就是我们TCP报文的有效载荷吗?

在这里插入图片描述

如何分用?

还记得我们报头上有个目的端口号字段吗?在操作系统里,会存在一张hash表,而port则是对应的key值,value值就是我们的进程PCB。所以操作系统可以通过报文中的目的端口号,去找到该端口号绑定的进程PCB。

在这里插入图片描述

找到了进程的PCB之后,PCB内部又有一个files_struct的结构体,里面有fd_arr[]数组,数组存储的是描述文件结构体的指针*file,数组的下标则是对应的文件描述符fd。而此时操作系统会创建一个新的文件,这个新的文件的下标就是我们经常见到的sock。而此时传输层并不知道sock是多少,但是当我们进行read的时候,会把sock传进去。此时传输层就知道了sock是多少,并找到PCB中sock对应的文件。把数据拷贝到该文的缓冲区。

在这里插入图片描述

这其中还有很多细节,不过我们大致知道一个流程就行了。所以,数据是通过TCP层拷贝到sock套接字的文件缓冲区的!那么这也意味着,TCP内部也是有缓冲区的! 因为客户什么时候从TCP上读取数据是不确定的!这就意味着TCP必须要有保存数据的能力!

TCP的可靠性

为什么网络传输的时候,会存在不可靠的问题?

很简单,因为距离太远!就好比你和你的室友说话,离的越近他听到的就越清除。如果你和他隔了50米说话,人家还能听清吗?人家听不清甚至听不到!这就是你发送的信息丢失了!而在网络中也一样,随着距离的变长,数据丢失的可能就越大。如果数据丢失了,那么我们是不是要采取相对应的策略。去解决这些问题呢?而解决这些问题就提高了可靠性。

不可靠问题常见的有哪些不可靠的场景?

1. 丢包

顾名思义,你的报文丢失了。也就是你的数据丢失了,这是一种不可靠的场景。

2. 乱序

这个也很好理解,比如你发送了5个报文,分别是以 1, 2 ,3 ,4 ,5的顺序发送的,可是对端接收却以5,2,3,4,1接收的。就好比你和你女神发:你喜欢我不。 结果你女神那边却收到:我不喜欢你。这样你的爱情直接毁于一旦了,所以肯定是不可靠的。

3. 校验错误

就是检查你的报文有没有不合理的地方。

4. 重复

你发送了一条报文,但是你以为对方没收到,然后发送了多条报文。但是对方其实都收到了,就说明你发送了重复的报文,这也是不可靠的一种场景

当然,不可靠的场景还有很多,这里就不一 一细说了。

确认应答机制

抛出一个问题:如果距离长了,存不存在绝对的可靠性?

先说结论,答案是不存在!

为什么呢?

就好比我们的A 和 B 说话,他俩之间隔了500米。A 对 B 说,你吃饭了吗?

在这里插入图片描述

这时候B收到了消息,但是A并不知道B有没有收到消息。所以这时候B回了一句: 吃了!

在这里插入图片描述

当A收到"吃了"这条消息的说话,A 可以肯定的是,他的上一条消息 "你吃饭了吗?"是被对方收到了的!但此时B并不知道A是否收到自己发送的消息。所以此时A又进行了回复。

在这里插入图片描述

A向B发送"吃的什么呀?",此时B也知道,他的上一条消息"吃了"是被A接收到了的!但此时A也并不知道自己新发的消息"吃的什么呀?"是否被B接收到。

再举个例子,你在宿舍叫你的室友。但是他没有一点反应,这就是你没有收到应答,你没有收到应答,是不是你就会认为他没听见?你会认为你的消息丢包了。所以你会再叫一遍。这时候他听到了,点了点头,或者看了你一眼,或者和你说话。这些都是对方听到你消息的一种应答。

通过上面的例子,我们可以得到结论:

1. 我们认为,只有收到了回复,我们才能100%确认对方收到了我们发送的历史消息

2. 双发通信,一定存在最新的数据没有应答!而最新的这一条消息无法保证可靠性!

32位序号与32位确认序号

32位序号代表TCP缓冲区的数组下标。每次发送时,都会把这个下标发给对端,当对端接收时,返回应答时,会填入32位确认序号。32位确认序号填的是这个序号之前的报文,已经全部收到了。

在这里插入图片描述

而我们都知道,如果发送发出去的顺序和对端接收的顺序不一致,也就是乱序的。那么这是不可靠的,因为有可能是客户端发送一批报文,服务器再给出一批应答。这种情况TCP是不能保证接收的时候是有序接收的,而这时候就可以通过确认序号对接收来的报文进行排序,这样交给上层时就是有序的。也就是说按什么顺序发,就按什么顺序收。

在这里插入图片描述

为什么报文不只设置一个序号?

为什么报文设置2个序号,而不是一个序号? 反正也只是确认一下。 这是因为TCP是全双工的!再保证自己接收数据的情况下也要发送数据!所以这也就意味着仅仅一个序号是不行的!

16位窗口大小

我们都知道,TCP是有缓冲区的。如果上层迟迟不拿数据,或者服务器压力太大。会导致缓冲区的数据不能及时取走,如果最后服务器的接收缓冲区已经被打满了。那么客户端是否还要发送数据呢? 如果服务器的接收缓冲区快满了,那么你的客户端发送多少数据呢?如果服务器此时的缓冲区只剩下5个字节可用了。可是你的这一个TCP报文却发送了100字节。是不是意味着有95字节,没地方放了?所以为了保证合理的传输数据,就引入了16位窗口大小的概念。

而这个16位窗口大小,就是用来告诉对端,自己的接收能力!告诉对端,自己能接收多少数据,所以16位窗口大小填的是自己的接收长度!!然后对端收到这个报文后,知道了你的接收能力!就会根据你的接收能力给你传输适合大小的数据!

在这里插入图片描述

6位标志位

我们要先明白6位标志位的意义是什么,我们都知道sock套接字再创建时都要指明它的协议类型,是udp通信还是tcp通信还是…所以我们的TCP报文也不例外,**我们的TCP报文也有类型!**而这个6位标志位就是代表着报文的类型。

在这里插入图片描述

ACK标志位(acknowledgment)

ACK是一个确认应答标志位,我们上面说过。TCP最新的一条报文是无法保证可靠性的!所以如果你收到了对方的消息,你要告诉它你收到了!你就需要把ACK标志位由0置为1。再发生给对方后,对方就知道你收到了它的报文(这里会有丢包问题,后面的文章会讲解解决策略)。

SYN标志位(synchronization)

我们都知道TCP是面向连接的,而TCP的连接规则是三次握手。当你客户端向服务器发起连接时,那么TCP报文需要把SYN标志段设置为1。这样服务器接收到你这个报文时,就知道你是想和服务器建立连接。随后服务器会返回一个SYN + ACK都被设置了的报文,证明服务器收到了你的连接请求并和你建立连接。而这个过程就是TCP三次握手过程!具体的三次握手过程以及为什么要三次握手,后面会有详细讲解。

FIN标志位(finish)

我建立连接需要SYN标志位告诉服务器,我要建立连接了!

那么我们如果要断开连接时,是不是也要告诉服务器,我要断开连接了!(直接拔电源除外…)

所以当我们断开连接时,客户端(一般由客户端主动断开连接)会向服务器发送FIN为1的标志位的报文。告诉服务器,客户端要断开连接了!随后服务器给你应答后,也会给你发送一个FIN报文。你再给服务器发送ACK确认后,那么连接就断开了,这个过程也就是四次挥手。四次挥手详细过程后面会有讲解。

URG标志位(urgent)

我们上面说了32位序号可以用来对报文排序,让报文有序的交付给上层。 但是如果有的报文想搞特殊,想插队咋办?那们只需要把TCP报文的URG标志位设置位1。这样TCP收到这个报文不会把这个报文加入排序,而是立即处理这个报文。

而这个报文需要被尽快处理的数据在哪?

TCP报文中还有一个字段,那就是16位紧急指针

这个指针存的是在有效载荷中的偏移量!

那么紧急处理的数据占多少个字节呢?答案是1个字节!而这个数据我们称之为带外数据

用到URG标志位的场景非常的少,很少会用到。 如果你想服务器立马区帮你完成某一件事,你可以用上URG标志位。带外数据设置为 0,则返回服务器的健康状态…,设置为1,则去调用一个进程…等等。

PSH标志位(push)

当对端的接收缓冲区已经满了的时候,而你这边的会定时的发送TCP报文,收到对方的应答之后去查看对方的接收能力。可是试了几次,对方还是无法接收你报文的时候。这边已经忍无可忍了,就会把PSH设置为1,去催促对端让对端把数据赶紧取走。如果你是故意不read的,那没办法,人家也拿你没办法。我们都知道read会等待条件是否就绪,如果条件不就绪就会阻塞。而当收到带有PSH被设置的报文时,就会尽快的让read的等待条件就绪,以至于让上层读取数据后恢复自己的接收能力。这样这边的数据就可以发送了。所以,PSH就是让对端的read条件尽快就绪! 具体细节和多路转接有关,后面的博客会更新多路转接相关的知识。

RST标志位(reset)

我们上面说过,当程序结束时,要断开连接。但是有人不按套路出牌,直接拔电源让电脑关机。这样就没机会发送断开连接的报文。所以就会出现一种场景,就是服务器和客户端已经建立了连接。但是服务器直接操作系统重启了,也没来得及断开连接。而此时客户端也没有给服务器发送消息。等到服务器主机重启后重新运行服务进程时,你的客户端此时还认为是和服务器建立了连接的,但此时服务器刚刚重启,不认得客户端。所以客户端给服务器发送报文时,此时的服务器就很奇怪。对端怎么直接把报文发过来了?不是要先建立连接吗? 所以此时服务器就会在应答报文上设置RST标志位。意思就是连接重置!

在这里插入图片描述

还有一种情况也会发送重置RST,那就是三次握手失败的情况!在客户端最后一次ACK没有被服务器收到的时候。客户端认为自己已经和服务器建立了连接,而服务器却认为没有和客户端建立连接。所以此时客户端直接给服务器发送数据报文,服务器也会返回重置了RST的报文应答。

在这里插入图片描述

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

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

相关文章

OpenAPI Typescript Codegen 的基本使用

下载 axios npm install axios OpenAPI Typescript Codegen 官网:https://github.com/ferdikoomen/openapi-typescript-codegen 安装 OpenAPI Typescript Codegen npm install openapi-typescript-codegen --save-dev–input:指定接口文档的路径、url …

FPGA - 滤波器 - IIR滤波器设计

一,IIR滤波器 在FPGA - 滤波器 - FIR滤波器设计中可知,数字滤波器是一个时域离散系统。任何一个时域离散系统都可以用一个N阶差分方程来表示,即: 式中,x(n)和y(n)分别是系统的输入序列和输出序列;aj和bi均为…

【机器学习】Dify:AI智能体开发平台版本升级

一、引言 关于dify,之前力推过,大家可以跳转 AI智能体研发之路-工程篇(二):Dify智能体开发平台一键部署了解,今天主要以dify为例,分享一下如何进行版本升级。 二、版本升级 2.1 原方案 #首次…

Python对象复制竟然有这么多种方式,赶紧学起来!

目录 1、浅拷贝:copy模块的copy()函数 📋 1.1 浅拷贝原理揭秘 1.2 实战演示:列表与字典的浅拷贝 列表浅拷贝示例 字典浅拷贝示例 1.3 注意事项:共享引用与独立对象 2、深拷贝:copy模块的deepcopy()函数 📌 2.1 深拷贝实现机制解析 2.2 深拷贝优势分析 2.3 深度…

(微服务实战)预付卡平台支付交易系统消费业务流程设计

1 交易系统技术架构 预付卡支付交易系统采用Dubbo3作为底层框架,支付交易系统分为账户系统、清结算系统、支付网关、核心支付系统等模块。系统整体采用微服务架构,容器化部署。 2 消费业务流程设计 预付卡系统消费场景分为线上和线下,线…

【安装和引入 PyTorch 包,快来收藏】

在本文介绍 PyTorch 中一些最常用的命令和设置。 一个完成的 PyTorch 工作流程。 安装和引入 PyTorch 包 最好的安装教程就是去官方网站:https://pytorch.org/get-started/locally/ 安装结束之后,直接引入整个 torch 包: import torch或…

【机器学习300问】122、RNN面临哪些问题?

循环神经网络(RNN)主要面临梯度消失和梯度爆炸两个核心问题,这严重影响了其处理长期依赖的能力。此外,还存在一些其他的技术挑战。 一、两个主要问题 (1)梯度消失和梯度爆炸问题 这是RNN中最显著的问题之…

示例:WPF中绑定枚举到ComboBox的方式

一、目的:在开发过程中,经常会需要把枚举绑定到ComboxBox下拉列表中,其实方法有很多,这里面通过MarkupExtension扩展GetEnumSourceExtension去绑定到列表 二、实现 定义GetEnumSourceExtension类 public class GetEnumSourceExte…

Elasticsearch-使用Logstash同步Mysql

1.安装logstash es服务器版本必须和logstash版本一致 7.9.2 在/usr/local/src/下新建logstash文件夹,解压 下载logstash后查看是否安装成功,在logstash的bin目录下输入指令: ./logstash -e input { stdin { } } output { stdout {} }2.my…

【乳业巨擘·数字革命先锋】光明乳业:上市公司科技蜕变,搭贝低代码引领未来新纪元

在这个由科技编织的未来世界里,光明乳业股份有限公司以巨人之姿,傲立于乳业之巅,以其无与伦比的胆识与魄力,引领了一场震撼业界的数字化革命。与低代码领域的创新领袖——搭贝的强强联合,不仅标志着光明乳业在数字化转…

吉林省教育学院学报杂志社吉林省教育学院学报编辑部2024年第5期目录

“研培一体”理论与实践 教师培训管理共同体的职能定位与价值追求 张岩; 1-3 数字化转型背景下教师培训工作的发展路径 李春光; 4-6 挖掘数智潜能,推进教师培训融合创新 鲍赫; 7-9《吉林省教育学院学报》投稿:cn7kantougao163.com 精准培…

AcWing 1273:天才的记忆 ← ST算法求解RMQ问题

【题目来源】https://www.acwing.com/problem/content/1275/【题目描述】 从前有个人名叫 WNB,他有着天才般的记忆力,他珍藏了许多许多的宝藏。 在他离世之后留给后人一个难题(专门考验记忆力的啊!),如果谁…

RockChip Android12 Settings一级菜单

一:概述 在之前的文章中对Android8.1 Settings的流程进行了说明,本章将针对Android12 Settings一级菜单的加载逻辑进行详细说明,Settings版本之间的差异不是很大,有兴趣的同学可自行学习,本文不在做赘述。 Android8.1 Settings说明:RockChip Android8.1 Settings-CSDN博…

创邻科技张晨:期待解锁图技术在供应链中的关联力

近日,创邻科技创始人兼CEO张晨博士受浙江省首席信息官协会邀请,参加数字化转型与企业出海研讨会。 此次研讨会旨在深入探讨数字经济时代下,企业如何有效应对成本提升与环境变化所带来的挑战,通过数字化转型实现提效增益&#xff…

解决Unity-2020 安卓异形屏黑边

背景 Unity 2020.3.17 版本开发的游戏,打apk包,发现两个问题 如图下午所示,实体白色导航栏,阻挡了整个安卓UI界面,难看还影响美观。 安卓系统 12-13 版本手机,异形屏。一侧安全区黑边遮挡,占空间…

第2讲:pixi.js 绘制HelloWorld

基于第0讲和第1讲,我们增添了vite.config.ts文件。并配置了其他的http端口。 此时,我们删除掉没用的东西。 删除 conter.ts、typescript.svg 在main.ts中改成如下内容: import {Application, Text} from pixi.js import ./style.css// 指明…

数组元素的内存地址计算【数据结构与算法C#版】

数组元素被存储在连续的内存空间中,这意味着计算数组元素的内存地址非常容易。给定数组内存地址(首 元素内存地址)和某个元素的索引,我们可以使用下方图 所示的公式计算得到该元素的内存地址,从而直接 访问该元素。 观…

C# Winform图形绘制

WinForms 应用程序中的控件是基于窗体的,当控件需要重绘时,它会向父窗体发送一个消息请求重绘。但是,控件本身并不直接处理绘制命令,所以你不能直接在控件上绘制图形。 解决方法: 重写控件的OnPaint方法使用CreateGr…

五大维度大比拼:ChatGPT比较文心一言,你的AI助手选择指南

文章目录 一、评估AI助手的五个关键维度二、ChatGPT和文心一言的比较 评估AI助手的五个关键维度,以及ChatGPT和文心一言的比较如下: 一、评估AI助手的五个关键维度 界面友好性 : 评估标准:用户界面是否直观易用,是否…

Java基础 - 练习(一)打印等腰三角形

Java基础练习 打印等腰三角形,先上代码: public static void main(String[] args) {// 打印等腰三角形System.out.println("打印等腰三角形:");isoscelesTriangle(); } public static void isoscelesTriangle() {// for循环控制行…