传输层协议UDP和TCP

news2025/5/13 18:34:30

传输层协议UDP和TCP

  • 1、UDP
  • 2、TCP
    • 2.1、TCP协议段格式
    • 2.2、确认应答(ACK)机制
    • 2.3、超时重传机制
    • 2.4、连接管理机制
    • 2.5、理解CLOSE_WAIT状态
    • 2.6、理解TIME_WAIT状态
    • 2.7、流量控制
    • 2.8、滑动窗口
    • 2.9、拥塞控制
    • 2.10、延迟应答
    • 2.11、捎带应答
    • 2.12、面向字节流
    • 2.13、粘包问题
    • 2.14、TCP异常情况
    • 2.15、用UDP实现可靠传输
  • 3、TCP全连接队列和tcpdump抓包

1、UDP

传输层:负责数据能够从发送端传输接收端。
再谈端口号:端口号(Port)标识了一个主机上进行通信的不同的应用程序。
在这里插入图片描述
如图,主机A上有许多服务,那么当传输层接收到数据,如何得知要将数据交给上层的哪个进程呢?网络通信本质就是进程间通信。所以就需要端口号来标识要将数据交给上层的哪个进程。一个端口号只能被一个进程绑定,而一个进程可以绑定多个端口号。

在这里插入图片描述
如图:客户端B向服务器发起请求,客户端A的web浏览器有两个页面向服务器发起请求。服务器要将响应的资源返回,而请求的时候会携带自己的源IP地址和源端口号,因此服务器将来返回的时候就可以根据IP地址找到主机,但是对于客户端A的浏览器请求了两个不同的页面,所以还需要端口号来区分要交给谁,而不会给反了或给错了。

所以之前我们是通过源IP+源端口+目的IP+目的端口四元组来标识一个网络通信的。那么实际上源IP和目的IP是添加在IP报头中的,然后源端口和目的端口是添加在TCP首部的,并且还需有一个协议号来标识传输层用的是什么协议。所以现在就通过上面的四元组+协议号来标识一个通信。

0 - 1023:知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议,他们的端口号都是固定的。
1024 - 65535:操作系统动态分配的端口号. 客户端程序的端口号,就是由操作系统从这个范围分配的。

cat /etc/services:可以查看一些知名端口。


UDP协议:
在这里插入图片描述
UDP协议报文如图:第一行32位,4个字节,前十六位表示源端口号,后十六位表示目的端口号。第二个四字节表示16位UDP长度和16位校验和。16位UDP长度是整个报文的长度,也就是报头8个字节加上数据的长度。如果校验和出错,就会直接将报文丢弃。

1、UDP如何做到解包的?
在读取UDP报文的时候,直接读取前八个字节,就是UDP报文的报头,剩下的就是有效载荷了。

2、UDP如何做到分用?
UDP报头里面就有16位目的端口号,根据16位目的端口号就可以找到进程。

3、接收方收到的UDP报文可能有多个黏在一起,这就是粘包问题。那么操作系统是如何准确的把一个UDP报文读上来呢?
UDP报文的前八个字节就是固定的报头,读取前八个字节将16位UDP长度提取出来,然后将长度减8算出来的就是有效载荷的长度,就可以根据这个长度去读取数据了。
16位UDP长度,这种自己报头里会描述有效载荷的特性我们称为自描述字段。

在这里插入图片描述
上图就是Linux内核中UDP报头的结构体信息。

在这里插入图片描述
应用层发送数据hello,交给下层,我们知道操作系统要对报文进行管理,所以struct sk_buff就是一个一个的报文。head指针指向数据头部,end指向尾部。并且之前也说了TCP全双工是存在两个队列的,一个接收队列一个写队列。
在这里插入图片描述
那么现在报头无非就是两步,第一步:将head指针往前移动udphdr大小个字节。第二步:接着将指针强转成struct udphdr*然后就可以访问里面的成员,对里面的成员进行赋值。

UDP的特点:
无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接。
不可靠:没有确认机制,没有重传机制。如果因为网络故障该段无法发到对方,UDP 协议层也不会给应用层返回任何错误信息。
面向数据报:不能够灵活的控制读写数据的次数和数量。应用层交给 UDP 多长的报文,UDP原样发送,既不会拆分,也不会合并。

UDP的缓冲区:
UDP没有真正意义上的发送缓冲区。调用 sendto 会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。
UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP报文的顺序和发送UDP报文的顺序一致。如果缓冲区满了,再到达的 UDP 数据就会被丢弃。

比如主机A给主机B发送的顺序是ABC,而主机B接收到的顺序可能就是BCA,这也是属于不可靠传输的一种。

我们注意到,UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含 UDP首部)。然而64K在当今的互联网环境下,是一个非常小的数字。如果我们需要传输的数据超过 64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼装。

基于UDP的应用层协议:
NFS:网络文件系统
TFTP:简单文件传输协议
DHCP:动态主机配置协议
BOOTP:启动协议(用于无盘设备启动)
DNS:域名解析协议


2、TCP

TCP全称为"传输控制协议(Transmission Control Protocol)"。人如其名,要对数据的传输进行一个详细的控制。

在这里插入图片描述
TCP有两个缓冲区,一个发送缓冲区一个接收缓冲区,当我们调用write函数时,本质是将数据拷贝到发送缓冲区中,对方调用read获取数据时,本质上是从接收缓冲区中拷贝数据。而发送数据本质就是将主机A的发送缓冲区的数据拷贝到主机B的接收缓冲区中,所以网络通信的本质就是拷贝。
上层将数据拷贝到发送缓冲区,本质就是拷贝给操作系统,未来数据发送的相关问题:什么时候发、发多少、出错了怎么办等,都是由操作系统自主决定的,所以TCP叫做传输控制协议。而UDP不存在发送缓冲区,write之后将数据交给下层,UDP做不到传输控制。


2.1、TCP协议段格式

在这里插入图片描述
如图,TCP报文包含报头和数据,其中前20个字节是固定的,图中就是五行,每一行四个字节,总共20字节。第一行为16位源端口、16位目的端口。第二行32位序号。第三行32位确认序号。第四行,4位首部长度,保留六位,还有六个标志位,16位窗口大小。第四行有16位校验和与16位紧急指针。
另外TCP还可以携带选项,如果不带选项就是20字节的报头+数据。

1、TCP是如何解包的?
首先读取前20个字节的固定长度,然后提取4位首部长度,根据4位首部长度的大小就可以获取完整的TCP报头,这个4位首部长度是包含固定的20字节+选项的长度的。那有人就会说了,4位首部长度最大就是1111,转换成十进制就是15,连前二十个字节都表示不了?
4位首部长度是有基本计算单位的,它的基本单位是4字节。
4位首部长度的取值范围为0000->1111,也就是[0,15],还需要再乘以4,所以最后4位首部长度可以表示的范围就是[0,60]。但是TCP前面20字节是固定的,因此实际取值返回就是[20,60]。

比如提取出来的4位首部长度是8,乘以基本单位4字节就是32字节,32字节减去固定的20字节还剩下12字节,说明剩下的12字节就是选项的长度。这样就可以读取整个TCP报头,那么剩下的就是数据了。那么如果今天TCP报头没有选项,TCP报头就只有20字节,那么对应的首部长度就是20/4=5。

2、TCP是如何分用的?
读取固定长度的前20个字节,报头中含有16位目的端口号,提取出16位目的端口号,就可以知道要将数据交付给上层的哪个进程。

下面来看一下Linux内核中的TCP报头结构体:
在这里插入图片描述


2.2、确认应答(ACK)机制

在这里插入图片描述
客户端给服务器发送数据,这个报文在网络上跑也是需要花时间的。那么客户端怎么知道我发出去的报文是否被服务端收到了呢?我发出去的报文是否因为某些原因丢失了呢?客户端是无法得知的。因此就需要服务端对客户应答,当服务端接收到客户端发送的报文后,需要对客户端做应答。
同样的,服务端给客户端发数据,客户端也需要应答,这种策略就是确认应答机制。
那么服务端给客户端作应答,表示我收到你发给我的报文了,那么服务端如何得知客户端是否收到我的应答呢?所以就需要客户端对服务端的应答继续做应答,然后客户端又需要知道服务端是否接收到我的应答,所以又需要服务端继续做应答。那么如果这样就会陷入了死循环。我们发现长距离通信的时候,其实没有100%的可靠性!因为总有一条最新的消息是没有应答的!

在这里插入图片描述
当客户端给服务端发送数据后,服务端接收到数据需要对客户端做应答,那么此时服务端就不再关心我的应答是否被客户端接收到了,因为是客户端要操心我的数据服务端有没有接收到。当客户端接收到应答就说明我之前发送的数据服务端接收到了,保证了老的消息是可靠的,保证了客户端到服务器的可靠性,不需要再对服务端的应答做应答了。如果客户端没有接收到应答,那么可能是服务端没有接收到数据,也可能是服务端的应答丢失了,这时候客户端会再去问服务端的。
所以老消息是有应答的,保证100%可靠。
那么此时从客户端到服务端就是可靠的。同样的,服务端给客户端发送数据,客户端也需要做应答,如此一来,也保证了服务端到客户端的可靠性。
所以TCP是可靠的,它的核心协议就是确认应答。

在这里插入图片描述
所以现在客户端发送request,服务端就需要确认应答。同样的,服务端给客户端发送数据,客户端也需要对服务端做应答。
此时客户端给服务端发送的request是TCP报头+有效载荷,也就是一个完整的报文。而服务端给客户端的确认应答是一个裸的TCP报头。所以双方在发送数据的时候,至少都要有一个报头。


再谈序号和确认序号:
上面我们的通信方式是:客户端给服务端发送消息,然后服务端做应答,客户端接收到确认应答后然后再给服务端发送数据。这种通信方式是串行的,这是我们第一阶段的认识,那么这种通信方式效率就很低。
在这里插入图片描述
实际上,客户端会给服务端发送一批报文,比如上图客户端C给服务端S发送了四个报文,而每个报文都需要做应答,因此服务端在接收到报文后再给客户端做应答,每一个报文都要有应答。通过这种方式,既可以保证可靠性同时又提高了效率。但是问题是,服务端给客户端应答,如果客户端只收到了三个应答,那么客户端如何得知这三个应答针对的是哪三个报文呢?

在这里插入图片描述
因此客户端给服务端发送数据的时候,需要给每个报文带上编号,这个编号就是序号。比如客户端给服务端发送的四个报文编号分别为10、20、30、40。将来服务端给客户端确认应答的时候,应答往往是收到的报文序号的值再加1,比如服务端收到客户端发送的编号位10的报文,将来应答的就是11,收到20,应答就是21。所以给报文带上序号,就可以对报文进行区分了。
服务端给客户端返回的序号称为确认序号,确认序号=序号+1。表示序号之前的内容已经全部收到了。
比如客户端给服务端发送的报文序号为10,服务端收到后给客户端作应答,确认序号为11。客户端再收到服务端的应答后就知道,11号之前的内容对方已经全部收到了。

报文携带序号还有另外一个意义。当客户端给服务端发送报文,比如按照10、20、30、40的顺序进行发送的,但是服务端在接受的时候并不一定是按照10、20、30、40的顺序接收的。因为网络可能存在各种各样的情况,所以可能后发送的先到了,先发送的反而后到。而报文如果是乱序的,也是不可靠的表现。因此就需要根据序号来对接收到的报文进行排序。
服务端在接收到报文后可以根据报文的序号进行升序排序,这样就保证了服务端缓冲区的报文是有序的。

为什么要有两个序号?
服务端接收到客户端发送的数据,比如对应的报文序号为10,那么服务端直接设置序号11给客户端返回做确认应答就好了,也就是说它们使用一个序号不就可以了吗,为什么要有序号和确认序号呢?
服务端在给客户端做应答的时候,如果只是单纯的应答,那就是裸的TCP报头,但是有没有可能服务端也要给客户端发送数据呢?当然是有可能的,那么这时候服务端给客户端发送的就是一个报文,这个报文既是对客户端之前发送数据的应答,同时也给客户端发送数据。这种情况称之为捎带应答机制。TCP报文在很大的概率上,既是应答,又是数据。
所以这时候就需要序号和确认序号了,确认序号用来表示之前客户端给我发送的数据我服务端接收到了,同时我也要给客户端发送数据,所以也要给报文设置序号,方便将来客户端做应答。那么将来客户端如果还要发送数据,那发送的报文就是既是应答也是数据,如果没有数据要发送了,那就是单纯的应答。
因此,在TCP通信中,大部分情况下报文既是应答,又携带了数据。这才是真实的TCP通信。


再谈16位窗口大小:
在这里插入图片描述
如果对方来不及接收数据呢?
客户端给服务端发送数据,假设服务端接收缓冲区有100字节,现在已经有80字节的数据了,还剩下20字节的数据。服务端上层还在进行数据的处理,来不及将这80个字节的数据取走,如果这时候客户端再给服务端发送一大批数据的话,那么接收缓冲区就会满,满了服务端就接收不了数据了,因此服务端就会将报文直接丢弃。那么这种做法当然是可以解决的,如果服务端直接将报文丢弃,就不会给客户端做确认应答,因此客户端没有接收到确认应答就会重新给服务端发送报文。
但是操作系统不做浪费时间,浪费空间的事情。

客户端今天发送了一个报文,这个报文经过网络千里迢迢到达了服务端,占用了各种网络资源,结果服务端直接就丢弃了,那不就

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

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

相关文章

浅谈大语言模型原理

1.反向传播算法 背景 反向传播算法是当前深度学习的核心技术。 神经网络 x是输入,o是输出,w是需要训练的参数(w有初始值)三层全连接的神经网络:输入层、隐藏层、输出层 激活函数 f ( x ) 1 1 x − 1 f(x)\frac…

Clickhouse 迁移到 Doris 的最佳实践

一、引言 在将数据从 Clickhouse 迁移到 Apache Doris / SelectDB Cloud 的过程中,涉及表结构迁移、查询语句迁移以及数据迁移等多个关键环节。每个环节都有其复杂性和需要注意的细节,本文将详细介绍这些内容及对应的最佳实践方法。 二、表结构迁移 &…

WebSocket的原理及QT示例

一.WebSocket 介绍 1.概述 WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议,它在 2011 年被 IETF 定为标准 RFC 6455,并由 RFC7936 补充规范。与传统的 HTTP 协议不同,WebSocket 允许服务器和客户端之间进行实时、双向的数据传输&a…

vue3:十二、图形看板- echart图表-柱状图、饼图

一、效果 如图展示增加了饼图和柱状图,并且优化了浏览器窗口大小更改,图表随着改变 二、 饼图 1、新建组件文件 新增组件EchartsExaminePie.vue,用于存储审核饼图的图表 2、写入组件信息 (1)视图层 写入一个div,写入变量chart和图表宽高 <template><div ref…

2025年best好用的3dsmax插件和脚本

copitor 可以从一个3dsmax场景里将物体直接复制到另一个场景中 Move to surface 这个插件可以将一些物体放到一个平面上 instancer 实体器&#xff0c;举例&#xff1a;场景中有若干独立的光源&#xff0c;不是实体对象&#xff0c;我们可以使用instancer将他变成实体。 paste …

HAProxy + Keepalived + Nginx 高可用负载均衡系统

1. 项目背景 在现代Web应用中&#xff0c;高可用性和负载均衡是两个至关重要的需求。本项目旨在通过HAProxy实现流量分发&#xff0c;通过Keepalived实现高可用性&#xff0c;通过Nginx提供后端服务。该架构能够确保在单点故障的情况下&#xff0c;系统仍然能够正常运行&#…

5.12 note

Leetcode 图 邻接矩阵的dfs遍历 class Solution { private: vector<vector<int>> paths; vector<int> path; void dfs(vector<vector<int>>& graph, int node) { // 到n - 1结点了保存 if (node graph.size() - 1)…

跨时钟域(CDC,clock domain crossing)信号处理

参考视频&#xff1a; 数字IC&#xff0c;FPGA秋招【单bit信号的CDC跨时钟域处理手撕代码合集】_哔哩哔哩_bilibili 一、亚稳态 原因是&#xff1a;建立时间和保持时间没有保持住。然后在下图的红框里面&#xff0c;产生亚稳态。因为电路反馈机制&#xff0c;最后大概率会恢复…

OBS studio 减少音频中的杂音(噪音)

1. 在混音器中关闭除 麦克风 之外的所有的音频输入设备 2.在滤镜中增加“噪声抑制”和“噪声门限”

智能手表 MCU 任务调度图

智能手表 MCU 任务调度图 处理器平台&#xff1a;ARM Cortex-M33 系统架构&#xff1a;事件驱动 多任务 RTOS RTOS&#xff1a;FreeRTOS&#xff08;或同类实时内核&#xff09; 一、任务调度概览 任务名称优先级周期性功能描述App_MainTask中否主循环调度器&#xff0c;系统…

S7-1500——零基础入门2、PLC的硬件架构

PLC的硬件架构 一,西门子PLC概述二,CPU介绍三,数字量模块介绍四,模拟量模块介绍五,其他模块介绍一,西门子PLC概述 本节主要内容 西门子PLC硬件架构,主要内容包括PLC概述、组成、功能及S7-1500 demo的组成与安装演示。 介绍了PLC的定义、功能、应用场合,以及与继电器控…

【PmHub后端篇】Skywalking:性能监控与分布式追踪的利器

在微服务架构日益普及的当下&#xff0c;对系统的性能监控和分布式追踪显得尤为重要。本文将详细介绍在 PmHub 项目中&#xff0c;如何使用 Skywalking 实现对系统的性能监控和分布式追踪&#xff0c;以及在这过程中的一些关键技术点和实践经验。 1 分布式链路追踪概述 在微服…

利用“Flower”实现联邦机器学习的实战指南

一个很尴尬的现状就是我们用于训练 AI 模型的数据快要用完了。所以我们在大量的使用合成数据&#xff01; 据估计&#xff0c;目前公开可用的高质量训练标记大约有 40 万亿到 90 万亿个&#xff0c;其中流行的 FineWeb 数据集包含 15 万亿个标记&#xff0c;仅限于英语。 作为…

【RabbitMQ】应用问题、仲裁队列(Raft算法)和HAProxy负载均衡

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 一、幂等性保障 什么是幂等性&#xff1f; 幂等性是指对一个系统进行重复调用&#xff08;相同参数&#xff09;&#xff0c;无论同一操作执行多少次&#xff0c;这些请求…

软件设计师-错题笔记-系统开发与运行

1. 解析&#xff1a; A&#xff1a;模块是结构图的基本成分之一&#xff0c;用矩形表示 B&#xff1a;调用表示模块之间的调用关系&#xff0c;通过箭头等符号在结构图中体现 C&#xff1a;数据用于表示模块之间的传递的信息&#xff0c;在结构图中会涉及数据的流向等表示 …

C#简易Modbus从站仿真器

C#使用NModbus库&#xff0c;编写从站仿真器&#xff0c;支持Modbus TCP访问&#xff0c;支持多个从站地址和动态启用/停用从站&#xff08;模拟离线&#xff09;&#xff0c;支持数据变化&#xff0c;可以很方便实现&#xff0c;最终效果如图所示。 项目采用.net framework 4.…

【深度学习】目标检测算法大全

目录 一、R-CNN 1、R-CNN概述 2、R-CNN 模型总体流程 3、核心模块详解 &#xff08;1&#xff09;候选框生成&#xff08;Selective Search&#xff09; &#xff08;2&#xff09;深度特征提取与微调 2.1 特征提取 2.2 网络微调&#xff08;Fine-tuning&#xff09; …

视觉-语言-动作模型:概念、进展、应用与挑战(下)

25年5月来自 Cornell 大学、香港科大和希腊 U Peloponnese 的论文“Vision-Language-Action Models: Concepts, Progress, Applications and Challenges”。 视觉-语言-动作 (VLA) 模型标志着人工智能的变革性进步&#xff0c;旨在将感知、自然语言理解和具体动作统一在一个计…

一键解锁嵌入式UI开发——LVGL的“万能配方”

面对碎片化的嵌入式硬件生态&#xff0c;LVGL堪称开发者手中的万能配方。它通过统一API接口屏蔽底层差异&#xff0c;配合丰富的预置控件&#xff08;如按钮、图表、滑动条&#xff09;与动态渲染引擎&#xff0c;让工程师无需深入图形学原理&#xff0c;效率提升肉眼可见。 L…

智慧城市综合运营管理系统Axure原型

这款Axure原型的设计理念紧紧围绕城市管理者的需求展开。它旨在打破传统城市管理中信息孤岛的局面&#xff0c;通过统一标准接入各类业务系统&#xff0c;实现城市运营管理信息资源的全面整合与共享。以城市管理者为中心&#xff0c;为其提供一个直观、便捷、高效的协同服务平台…