传输层协议UDP

一、重新认识端口号

在TCP/I 协议中,可以用 "源 IP","源端口号","目的 IP","目的端口号","协议号" 这样一个五元组来标识一个通信 (可以通过 netstat -n 查看);

1.1 端口号范围划分

0‑1023:知名端口号,HTTP,FTP,SSH 等这些广为使用的应用层协议,他们的端口号都是固定的。

1024‑65535:操作系统动态分配的端口号。客户端程序的端口号,就是由操作系统从这个范围分配的。但是也有一些服务会选择1024‑65535的端口号进行绑定:

端口 协议 服务 用途说明
1521 TCP Oracle Oracle 数据库默认端口
2049 TCP/UDP NFS Linux 网络文件共享服务
2181 TCP Zookeeper 分布式协调组件
2701 TCP Steam 游戏服务
3000 TCP Node/Grafana 前端开发服务器、监控面板
3306 TCP MySQL/MariaDB 最常用关系型数据库
5000 TCP Flask Python Web 开发默认端口
5432 TCP PostgreSQL 开源关系数据库
5672 TCP RabbitMQ 消息队列 AMQP 协议端口
6379 TCP Redis 内存缓存数据库
8000 TCP Django/FastAPI Python 后端常用端口
8080 TCP HTTP 备用 Tomcat、代理、Web 开发端口
8443 TCP HTTPS 备用 Jenkins、K8s Dashboard
9000 TCP MinIO 对象存储服务
9042 TCP Cassandra 数据库 CQL 访问端口
9092 TCP Kafka 消息队列服务端口
9200 TCP Elasticsearch 搜索引擎 REST 接口
11211 TCP/UDP Memcached 内存缓存
15672 TCP RabbitMQ 管理页面 Web 管理 UI
27017 TCP/UDP MongoDB NoSQL 文档数据库

1.2 认识知名端口号 (Well‑Know Port Number)

有些服务器是非常常用的,为了使用方便,人们约定一些常用的服务器,都是用以下这些固定的端口号:

1.ssh 服务器,使用 22 端口

2.ftp 服务器,使用 21 端口

3.telnet 服务器,使用 23 端口

4.http 服务器,使用 80 端口

5.https 服务器,使用 443

我们可以通过执行下面的命令,来看到这些知名端口号

bash 复制代码
cat /etc/services

一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定!

二、UDP协议

2.1 UDP协议的格式

UDP协议规定,UDP首部固定8 字节,4 个字段,每个字段 16 位。

16位源端口号是发送方进程的端口,目的端口号是接收方进程的端口。16位UDP长保存的是整个 UDP 数据报总长度(首部 + 数据),最小为 8(只有头部,无数据);最大为16 位,即65535 字节。

16位UDP检验和保存的是校验UDP首部+数据,用于检测传输是否出错。如果出错则直接丢弃报文。

数据(有效载荷)是向上层应用交付的数据,长度可变。

UDP协议是如何实现报头和有效载荷分离的呢?

UDP采用的是固定长度的报头,在固定长度的报头中,存在一个16位UDP长度,用于标识整个报文的长度。有了报文的长度和报头长度,就可以知道有效载荷的长度,也就能实现报头与有效载荷的分离了。

UDP中的有效载荷是如何分用的呢?

UDP 的有效载荷依靠端口号完成分用。客户端发送UDP报文时,UDP首部携带16位目的端口号,标识服务器上目标进程的端口。当报文到达传输层后,操作系统读取该目的端口号,根据端口号把 UDP报文中的有效载荷,交付给服务器上对应的应用进程,以此实现有效载荷的向上交付。

UDP叫做面向数据报协议,是面向数据报的,每一个 UDP 报文都有明确的长度。当接收方拿到 UDP 报文时,拿到的就是一个完整独立的数据报,报文与报文之间相互隔离,因此UDP 不会发生粘包问题。

UDP 报头本质上可以理解为逻辑上的结构体。操作系统大多使用 C 语言实现,协议头部在内存中是以结构体的形式组织。接收方拿到二进制报文之后,通过指针按照协议格式解析,就能直接提取出源端口、目的端口、长度、检验和等不同字段的内容。

与之对应,封装的过程本质上可以类比为结构体变量的拷贝。有效载荷每向下穿过一层网络协议栈,都会在数据前端追加当前层级对应的协议报头,而每一层报头都是结构化的数据,整个拼装流程,逻辑上近似于对结构体数据进行复制填充。

在操作系统内部,同一时刻会存在大量待处理、待转发的网络报文,操作系统需要统一调度、维护这些报文,因此要先通过数据结构描述报文信息,再将所有报文有序组织管理**(先描述,再组织)** 。Linux内核中专门使用sk_buff结构体 来承载、管理每一个网络报文。这套报文管理逻辑,和操作系统管理进程的设计思路高度相似:操作系统依靠 task_struct 结构体描述单个进程,再通过链表组织全部进程;同理依靠 sk_buff 描述单个报文,再用链表批量管理所有网络数据包。

而报文本身,本质上由两部分构成 :一是用于记录报文元信息、描述报文属性的sk_buff结构体变量 ,二是该结构体配套、在内核内存中专门开辟的缓冲区,缓冲区中存放完整的协议头部与传输数据。

报文贯穿整个协议栈,其封装与解包操作的核心实现方式,其实仅靠移动缓冲区指针即可完成。封装时向前移动指针,预留空间写入当前层协议报头;包时向后移动指针,跳过当前层头部直接取上层载荷。

每个套接字对应的sock结构中维护着接收队列与发送队列。当传输层UDP完成报文解封装,需要将数据交付给上层应用时,会剥离UDP报头,把承载应用数据的sk_buff挂载到对应套接字的接收队列,以此向上交付给应用层;而应用向下发送数据时,则会把封装好头部的sk_buff放入套接字发送队列,向下递交给下层协议栈。

2.2 UDP协议的特点

UDP协议是无连接、不可靠、面向数据报的:

无连接:知道对端的 IP 和端口号就直接进行传输,不需要建立连接;

不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP 协议层也不会给应用层返回任何错误信息;

面向数据报:不能够灵活的控制读写数据的次数和数量;

无连接、不可靠

前文提到过,当接收端校验UDP检验和时一旦发现数据出错,会直接丢弃该报文。又因为UDP属于无连接协议,不存在应答、重传机制,报文丢失后接收方不会向发送方反馈任何丢失通知,发送方也不会主动等待确认、不会重新发送丢失的数据,这也是UDP被定义为不可靠传输协议的核心原因。

面向数据报

应用层交给 UDP 多长的报文,UDP 原样发送,既不会拆分,也不会合并;

当使用UDP协议传输100 个字节的数据:如果发送端调用一次sendto,发送 100 个字节,那么接收端也必须调用对应的一次recvfrom,接收 100 个字节;而不能循环调用 10 次recvfrom,每次接收 10 个字节。正由于UDP面向数据报的特点,发送端发一次数据,接收端就得接收一次数据,所以UDP协议就不会存在粘包问题。

那既然UDP协议是不可靠的,为什么我们还要有这个协议呢?

所谓的不可靠,不是说数据传输不过去,而是指的是数据传不过去时,而是当出现丢包、错包时,协议本身不会感知、不会处理,不会保障数据一定送达。UDP不可靠,不代表它不可用。其次,可靠传输需要一系列复杂机制支撑,要做更多的工作也就更多。所以为什么TCP是可靠的,因为它面向连接,同时额外实现了确认应答、重传、流量控制、拥塞控制等大量保障逻辑来确保它是可靠的。UDP相于TCP来说工作更少,所以也更简单。当我们在一些对丢包数据不敏感的环境下,我们就可以使用UDP进行数据的分发。

所以我们不要把UDP的不可靠当作缺点,而是要当作其特点。在对实现逻辑要求简单、追求高实时性、并发用户规模大,或是局域网环境这类场景下,UDP会被更多采用。

2.3 UDP的缓冲区

UDP没有真正意义上的发送缓冲区。调用sendto会将数据直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。

UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃。

UDP socket既能读,也能写,所以UDP是全双工的。

2.4 使用UDP时的注意事项

我们注意到,UDP 协议首部中有一个 16 位的长度字段。也就是说一个 UDP 报文能够传输的最大长度是 64K(包含 UDP 首部)。

然而 64K 在当今的互联网环境下,是一个非常小的数字。

如果我们需要传输的数据超过 64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼装。

2.5 基于UDP的应用层协议

1.DNS(域名解析协议) 默认使用 UDP 53 端口。域名查询报文短小,不需要建立连接;只有响应报文很大的时候才会降级使用 TCP。

2.DHCP(动态主机配置协议) UDP:客户端端口 68,服务端端口 67。主机刚启动还没有 IP,无法建立 TCP 连接,所以用 UDP 广播获取 IP 地址。

3.TFTP(简单文件传输协议) UDP 69 端口。用于局域网简单传小文件,比如 PXE 网卡启动,实现简单,性能优先,自己在应用层做简单可靠性。

4.SNMP(简单网络管理协议) UDP 161/162 端口。网管设备监控,频繁轻量查询网络设备状态。

5.NTP(网络时间协议) UDP 123 端口。客户端向时间服务器同步系统时间,报文简短,追求低延迟。

6.RTP(实时传输协议) 用于直播、视频会议、VoIP 语音通话。跑在 UDP 之上,允许少量丢包,保证实时性;配套 RTCP 做控制。

7.QUIC(HTTP/3 底层) 基于 UDP 实现,在用户态实现类似 TCP 的可靠传输、拥塞控制;解决 TCP 队头阻塞,0‑RTT 握手。HTTP/3 = HTTP over QUIC over UDP。

8.BOOTP(引导程序协议) UDP:客户端端口 68,服务端端口 67,是DHCP的前身。无盘设备开机无IP地址,依靠UDP广播获取网络配置与引导文件路径,结构简单、无地址租期。

9.NFS(网络文件系统) 早期NFSv2仅支持UDP,NFSv3兼容UDP/TCP,新版NFSv4及以上仅支持TCP。多用于Linux局域网文件挂载共享,UDP版本主打低延迟局域网传输。

10.游戏自定义协议 很多网游、竞技游戏,自定义 UDP 报文,优先保证实时,允许少量丢包。

相关推荐
Elnaij1 小时前
Linux系统与系统编程(16)——日志、线程池的实现与线程安全
linux
szarron1 小时前
HTOOL‑SA12 + HT06 近场探头组合实操|手持设备工位 EMI 预兼容排查完整流程
运维·服务器·开发语言·网络·射频工程·频谱仪
杨云龙UP1 小时前
DB2 HADR 主备架构活动日志参数优化操作手册
linux·运维·服务器·数据库·db2·db2 hadr·日志参数调整
csdn_aspnet1 小时前
如何从电脑主机拷东西到VWmare虚拟机
linux·运维·服务器·windows·vmware·虚拟机
Vcaker2 小时前
Linux学习28-Kubernetes service
linux·运维·学习
为思念酝酿的痛2 小时前
Linux网络进程守护
网络协议·tcp/ip·udp
有梦想的咕噜2 小时前
Newtonsoft.Json (Json.NET) 常用方法汇总
linux·json·.net
码农小韩2 小时前
Linux应用开发(五)——线程
linux·操作系统·linux驱动·嵌入式软件开发·嵌入式操作系统·linux应用
czt_java2 小时前
网络核心初识:OSI七层、TCP/IP模型与数据传输全过程
网络·tcp/ip·php