传输层协议之UDP

1、端口号

        我们在应用层创建的套接字,是需要通过bind()接口绑定我们的IP地址与端口号的,这是因为数据从传输层向上交付到应用层时,需要用端口号来查找特定的服务进程。一般在网络通信时,用IP地址标识一台主机,用端口号表示该主机上特定的服务。所以一台主机上,可能同时存在各种不同的服务,每一种服务都有它对应的端口号。在传输层,系统会根据我们的端口号找到应用层的进程,将我们的数据交给应用层。所以网络通信最后实际上是把数据包向上根据端口号交付给特定进程。在TCP/IP协议中,使用五元组(源IP、源端口、目的IP、目的端口、协议号)保证通信中进程的一对一。

        端口号的是16位无符号整数,所以取值范围应该是0~65535,实际上在使用云服务器时,我们在bind()时,会发现有时候bind不了,因为在云服务器中的一些端口号是知名端口号,我们熟知的HTTP、FTP、SSH这些广泛使用的应用层协议,它们有自己的端口号,一般是固定不变的,被业界广泛承认固定,所以我们无法绑定这些端口号。知名端口号范围是0~1023,从1024~65535才是操作系统动态分配的端口号,一般客户端在随机分配端口的时候,是从这个范围中分配的。

        有两个问题,(1)一个进程能否绑定多个端口号?(2)一个端口号能否被多个进程绑定?答案分别是可以和不可以。数据在交付时,通过网络分层,一定是自底向上进行交付的,所以一定要保证从端口号到进程的唯一关系。而一个进程绑定多个端口号其实不破坏端口号到进程的唯一关系,所以是可以的。举个例子,我们可以写一个服务器,他有一个80号端口使用TCP协议,我们为其创建一个套接字,我们在创建一个使用UDP协议的套接字,绑定81号端口,在网络通信时既可以使用80号端口也可以使用81号端口,它们都与一个进程绑定,可以用不同的端口提供不同的服务,比如使用UDP端口发指令,使用TCP端口发数据。

UDP

1、报文格式        

        下面这张图就是UDP报文的格式分布,最下面有一个数据,代表应用层向下交付的所有数据,也成为UDP报文的有效载荷。所以我们在应用层使用套接字和sendto接口发送数据时,并不是直接讲数据发送到网络中去,而是发给了传输层,UDP协议会为我们的有效载荷进行添加报头封装,形成完整的UDP报文,进而进一步向下交付。

        具体来看,UDP报头里面包含16位源端口,16位目的端口,16位UDP长度和16位UDP校验和。在我们进行应用层代码编写时,写套接字时,我们绑定端口号为什么一定要使用uint_16?因为传输层和网络层时是属于操作系统内容,是由Linux内核进行管理的,在操作系统内部,端口号使用16位来表示的,这就决定了我们在应用层也要使用16位进行设置。16位校验和是UDP保证数据基本的正确性的一种策略。

        那么UDP报文在传输层是如何做封装和解包的?大部分的应用层协议为了让报头和有效载荷分离,要么规定特殊符号,比如\r\n来标识报头和有效载荷,要么直接在报头设置文件描述字段,比如在自己的报文前面带上长度。在UDP这里是怎么实现的呢?非常简单,UDP采用的策略叫做定长报头,传输层如果发现接收到的报文是一个UDP报文,内核中会直接把报文的前八个字节移走,移走之后再把有效载荷向上交付就可以了。这种策略可以说是所有协议中,设计最简单的,大小固定,在收发通信时,报头长度永远都是固定的,报头一旦固定约定好,客户端和服务器都认为报头是八个字节,所以再封装的时候加八个字节,解包的时候提取前八个字节,剩下的都是有效载荷。

        传输层上面还有很多的应用层协议(包括http、https、ssh),在传输层解包之后,后续的行为叫做对报文分用,什么是分用?是指传输层把报头和有效载荷分开之后,将有效载荷交给上层的特定协议。如何实现分用?报头中有16位目的端口号,系统根据目的端口号找到特定的进程,也就是应用层协议,将有效载荷向上交付,报文在向上交付到指定进程这个行为,其实就是交付到指定的应用层协议,可以认为应用层协议、进程、端口号是三位一体的

        我们可以看到报头中有一个字段叫做16位UDP长度,这个长度代表整个UDP报文的长度(包含报头),这也就意味着整个UDP报文的最大长度是2的16次方,也就是64kb,在当前的网络环境中,64kb其实是一个很小的数据量,如果我们要在传输层使用UDP协议传输大于64kb的数据,我们必须要在应用层将报文拆成64kb一下的数据,不然会发送失败。

        

2、UDP的特点

        (1)无连接。我们使用UDP协议实现一个服务器与客户端通信功能时,客户端建立套接字,bind自己的ip地址和端口号,并知名目的端口和ip,就可以直接发送消息,就像我们发送邮件时,是不需要确认自身与接收方的连接关系的。不像TCP在正式通信之前要经过三次握手确认两端已经连接好了才能发送数据。

        (2)不可靠。不论任何协议,在数据传输过程中可能发生丢包问题,一个报文在路上要经过无数个主句,无数个路由器,无数个转发设备进行转发,所以丢包其实是一个很常见的情况。关键在于不同的协议面对丢包的处理方式不同,UDP协议下,丢包了之后什么都不做,这就是所谓的不可靠。而TCP为了保证可靠性设计了一系列策略,超时重传、连接管理、流量控制、拥塞控制等。

        (3)面向数据报。首先,面向数据报我们可以类比为收发快递,当商家给我们发送三个快递,我们一定是要收三个快递的,不能只收一个或者一个半或者五个,不存在我们取快递时先取走半个,下次再取后半个,必须整发整取。在实际代码层面,服务器接收客户端报文,调用recvfrom接口时,要么别读,要么调用recvfrom成功时,必定读取到一个完整的报文,客户端发了十个报文,代表其调用了10次sendto接口,服务端也必须调用10次recvfrom接口,这个次数是一比一的(在不考虑丢包的前提下)。所以在写代码时,在UDP协议下,读取报文时不需要验证读取报文的完整性的,读取到报文之后只需要考虑数据的序列和反序列化(结构化)问题就可以了,而在TCP协议下,基于其面向字节流的特性,我们在应用层还需要设置一些验证报文完整性的策略。

        这里讲讲面向字节流,它的特点就是,发送端发数据可能发了十几二十次,但是接收方并不知道发送端发了多少次,上层也不知道报文与报文之间在传输层有什么样的边界,发了十多次,接收方可能一次就把数据读完了,也可能100次才读完。至于如何保证读取报文的完整性,程序员需要在应用层自己去定协议,自己从字节流中提取一个完整的报文。

3、UDP的缓冲区

        在讲UDP的缓冲区之前,先通过了解TCP的缓冲区对传输层缓冲区有一个系统的了解。

        这一段所讲的全部都是在TCP协议下的。在应用层我们调用的对套接字进行操作的接口,诸如read、write、send等等,我们在调用这些接口时并没有把数据从应用层,直接发送到网络里,我们只是通过这样的接口把数据交给了下层传输层,然后再继续向下交付。需要明确一点,我们用的这些网络IO接口,其实并不是直接发送,而是拷贝接口。在TCP这样的协议下,实际上通信双方会在各自的传输层维护发送和接收缓冲区,客户端和服务器都有,在调用send和write接口时,我们应用层中也要维护一块缓冲区,也许是一个char buffer[1024],我们从标准输入流中拿到数据也需要先保存到应用层的缓冲区中,接着调用send和write时,我们并没有直接将数据发送到网络中,而是把应用层的数据拷贝到自己的发送缓冲区中。拷贝好了之后,再由传输层,也就是操作系统,来控制发送缓冲区里的数据什么时候发?发多少?最终经过网络把数据放到对方的接收缓冲区里了。客户端读取时,也并不是从网络里读取上来,而是从接收缓冲区把数据拷贝到应用层中。TCP协议下,通信双方都维护了自己的发送缓冲区和接收缓冲区,可以同时实现两个方向的数据流动,互不干扰,这样的通信方式,称之为全双工。当应用层通过调用send或者write接口把数据交付给TCP之后,接口就直接返回了,相当于数据交付给了操作系统,后续什么时候发,发多少,丢包了怎么办,由操作系统来自主地决定(这也是为什么TCP叫做传输控制协议),应用层可以继续进行后续的业务,所以传输层缓冲区存在的价值,除了支撑全双工,还能够直接提高我们发送数据的效率。总而言之,用户把数据从应用层拷贝到对应的操作系统内部,操作系统再把数据从缓冲区刷新到网络里,有人放有人取,这个模型特别像之前提过的生产消费者模型,也是发送端和接收端进行解耦,解决忙闲不均问题。

        以上就是我们的传输层缓冲区的概念,可以联想到我们使用系统调用读写文件,我们基于文件描述符对文件进行读写,调用write时并不是把数据直接写到了磁盘上,因为IO太费时间了,调用write只是将数据拷贝到内核维护的一块缓冲区中,系统会等到数据到达一定数量或者读到\n再把数据刷新到磁盘上。

        现在来谈谈UDP,其实UDP没有真正意义上的发送缓冲区,它不需要发送缓冲区,应用层的数据交付到传输层,UDP直接添加上所谓的报头,直接交给在下一层,它不用支持可靠性机制,所以不需要暂时把数据暂存下来。我们应用层调用sendto把数据交给操作系统操作系统将数据传输给网络层,之后进行后续的传输动作。而UDP是具有接收缓冲区的,用于保存收到的数据,本质上,也是为了应对传输层收到数据了,而应用层还在对上一次接收到的数据进行处理而来不及接收的问题。这个接收缓冲区不保证数据有序,即不保证接收到的数据和发送的数据顺序一致,乱序本身是不可靠的一种情况。如果缓冲区中的数据满了,后续的数据会直接丢弃,这时UDP的处理策略。UDP整体上是支持通信双方同时读写的,因此它也具有全双工的特点。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小米起诉“小米”商标侵权,索赔500万!

近日浙江丽水有家叫小米的公司,因为商标侵权被小米科技起诉索赔500万,需要变更企业名称,官网也不能用“小米智能大家居”等,还有其它的赔偿,普推知产商标老杨分析,“小米智能大家居”“小米”,后…

ArduPilot开源飞控之AP_Mount_Topotek

ArduPilot开源飞控之AP_Mount_Topotek 1. 源由2. 框架设计3. 重要函数3.1 动态过程3.1.1 AP_Mount_Topotek::update3.1.2 AP_Mount_Backend::calculate_poi 3.2 基础能力3.2.1 AP_Mount_Topotek::healthy3.2.2 AP_Mount_Topotek::has_pan_control 3.3 设备功能3.3.1 AP_Mount_T…

第一次构建一个对话机器人流程解析(一)

1.问答机器人的组成 1.1 问答机器人的组成结构图 2. 问答机器人的组成-机器人的个人属性 所谓的机器人一般具备有个人的属性,这些属性固定,形成了机器人的个人偏好 在实现过程中,此处使用一个xml配置文件,配置了机器人的个人年…

卡码网KamaCoder 99. 岛屿数量

题目来源&#xff1a;99. 岛屿数量 C题解&#xff1a;来源代码随想录 懒得自己写了。直接搬运。。。 1. 深度优先搜索&#xff1a;它的循环在main函数里&#xff0c;遍历每个位置&#xff0c;判断 是否为陆地 及 是否访问过。 #include <iostream> #include <vecto…

自养号测评补单:速卖通卖家如何打造爆款?

在跨境电商的激烈竞争中&#xff0c;速卖通卖家们为了打造店铺的爆款商品&#xff0c;不仅需要紧跟市场趋势&#xff0c;还需理解爆款商品的生命周期。以下是一些实用的策略&#xff0c;帮助卖家们更有效地打造爆款&#xff1a; 一、精准选品策略 面对全球多样化的消费者群体&…

算法复杂度<数据结构 C版>

什么是算法复杂度&#xff1f; 简单来说算法复杂度是用来衡量一个算法的优劣的&#xff0c;一个程序在运行时&#xff0c;对运行时间和运行空间有要求&#xff0c;即时间复杂度和空间复杂度。 目录 什么是算法复杂度&#xff1f; 大O的渐近表达式 时间复杂度示例 空间复杂度…

Open-TeleVision——通过VR沉浸式感受人形机器人视野的远程操作

前言 7.3日&#xff0c;我司七月「大模型机器人(具身智能)线下营」群里的一学员发了《Open-TeleVision: Teleoperation with Immersive Active Visual Feedback》这篇论文的链接&#xff0c;我当时快速看了一遍&#xff0c;还是有价值的一个工作(其有受mobile aloha工作的启发…

编程题目积累(day5)

题目&#xff1a; 源数组a&#xff0c;将a中所有元素乘以2之后添加进a&#xff0c;则这个a就叫双倍数组&#xff0c;给你一个数组a&#xff0c;判断它是不是双倍数组&#xff0c;如果是则输出源数组&#xff0c;不是则输出空数组。 补充知识&#xff1a; python中枚举和字典…

一个很变态但是有用的变现手段:用AI技术搞电商模特图,接单接到手软~

前言 今天带大家拆解一个特别有趣的项目&#xff0c;必须得跟大家分享一下&#xff1a;用AI技术搞电商模特图。 是不是感觉挺科幻的&#xff1f;但这真不是科幻小说里的情节&#xff0c;而是咱们现实生活中已经实现的事情。 想想看&#xff0c;咱们平常在网上看到的那些漂亮…

【RHCE】基于密钥的身份验证(Win-Linux)

目的&#xff1a;要提⾼系统安全性&#xff0c;通过在 OpenSSH 服务器上禁⽤密码⾝份验证来强制进⾏基于密钥的⾝份验证。 1、一台虚拟机无需密码连接另一台虚拟机 .ssh目录 > 保存了ssh相关的key和一些记录文件 &#xff08;1&#xff09;生成密钥对 使⽤这个流程在本地…

基于pytesseract的OCR图片识别

简介 pytesseract是基于谷歌的tesseract的OCR包&#xff0c;支持识别一些简单的数字、字母、中文。 安装 安装引擎 下载地址&#xff1a;https://digi.bib.uni-mannheim.de/tesseract/ 一般是Windows 64位系统最新版&#xff1a; 如果要识别中文&#xff0c;注意选中中文…

如何在Mac上恢复已删除的文件?

多数 Mac 用户在将 Mac 出售或赠送给其他用户之前会擦除数据。这样做是必要的&#xff0c;因为它有助于保护隐私并防止任何人滥用您的机密数据。在大多数情况下&#xff0c;您会故意抹掉数据和文件。但在某些情况下&#xff0c;你做错了。 大多数人可能认为文件擦除和文件删除…

微软新必应对Edge的“全面”开放及其市场影响

前言 微软新必应Bing Chat的全面开放&#xff0c;特别是针对Edge浏览器用户的功能&#xff0c;将带来一系列重要的变化和影响。新必应不仅集成了GPT-4的智能提问功能&#xff0c;还加入了DALLE的AI绘画技术。这些创新将极大地增强用户的搜索体验和交互方式&#xff0c;对AI应用…

一个不完全编译导致的奇怪问题

1. 初始代码 文件a.h: typedef struct {int a;int b; } a_t;void set_a(a_t *in, a_t *out); a.c: #include "a.h"void set_a(a_t *in, a_t *out) {out->a in->a;out->b in->b; } main.c: #include "a.h" #include <stdio.h>int…

排序(三)——归并排序(MergeSort)

欢迎来到繁星的CSDN&#xff0c;本期内容主要包括归并排序(MergeSort)的实现 一、归并排序的主要思路 归并排序和上一期讲的快速排序很像&#xff0c;都利用了分治的思想&#xff0c;将一整个数组拆成一个个小数组&#xff0c;排序完毕后进行再排序&#xff0c;直到整个数组排序…

图解HTTP(5、与 HTTP 协作的 Web 服务器 6、HTTP 首部)

5、与 HTTP 协作的 Web 服务器 一台 Web 服务器可搭建多个独立域名的 Web 网站&#xff0c;也可作为通信路径上的中转服务器提升传输效率。 用单台虚拟主机实现多个域名 在相同的 IP 地址下&#xff0c;由于虚拟主机可以寄存多个不同主机名和域名的 Web 网站&#xff0c;因此…

阅读笔记——《Fuzz4All: Universal Fuzzing with Large Language Models》

【参考文献】Xia C S, Paltenghi M, Le Tian J, et al. Fuzz4all: Universal fuzzing with large language models[C]//Proceedings of the IEEE/ACM 46th International Conference on Software Engineering. 2024: 1-13.【注】本文仅为作者个人学习笔记&#xff0c;如有冒犯&…

跟着李沐学AI:简单损失函数

均方损失L2Loss 特点&#xff1a;当真实值y与预测值y相差较远时&#xff0c;梯度较大&#xff0c;参数更新较多。当预测值与真实值靠近时&#xff0c;梯度越来越小。 最小绝对值损失L1Loss 特点&#xff1a;当预测值与真实值相差较远时&#xff0c;梯度永远为常数&#xff0c;…

【Golang】map的使用

map声明的方式 //声明var m map[string]string//在使用map之前&#xff0c;先make&#xff0c;make的作用就是给map分配空间m make(map[string]string)m["lover"] "Yzx"m["friend1"] "Zxw"m["friend2"] "Zzc"…

SQL语法精选-如何拼接多列的值?

在做业务数据分析的时候&#xff0c;可能会遇到这样一个场景&#xff0c;需要将多个字段进行拼接&#xff0c;变为一个长字符串 比如年、月、日三个字段拼接成完整的日期&#xff0c;或者姓、名两个字段拼接成姓名列 这就需要用到SQL查询中串联&#xff08;拼接&#xff09;方…