【传输层协议】UDP协议 {端口号的范围划分;UDP数据报格式;UDP协议的特点;UDP的缓冲区;基于UDP的应用层协议}

本文主要是介绍【传输层协议】UDP协议 {端口号的范围划分;UDP数据报格式;UDP协议的特点;UDP的缓冲区;基于UDP的应用层协议},希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、再谈端口号

1.1 使用“五元组”标识一个通信

在这里插入图片描述

端口号(Port)标识了一个主机上进行通信的不同的应用程序

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

netstat 查看网络状态的重要工具


1.2 端口号的范围划分

在这里插入图片描述

  • 0 - 1023:这个范围内的端口号被保留用于一些特定的服务和应用程序,称为“系统端口”或“熟知端口”Well-Know Port Number)。例如:HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的。系统一般不允许用户自己绑定这个范围内的端口号。
  • 1024 - 65535:这个范围内的端口号大多数是可以自由绑定的,但也有个别例外,比如mysql绑定3306号端口。除去这些例外,其他的端口号可以由用户显式bind绑定,也可以由操作系统动态分配(客户端端口号绑定)。

常用的熟知端口

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

  • ssh服务器, 使用22端口
  • ftp服务器, 使用21端口
  • telnet服务器, 使用23端口
  • http服务器, 使用80端口
  • https服务器, 使用443端口

提示:在/etc/services文件中可以查看到系统中所有的知名端口号。我们自己编写的程序使用端口号时, 要避开这些知名端口号.

两个问题

  1. 一个进程是否可以bind多个端口号?当然可以,一个进程可以从多个端口收发数据。
  2. 一个端口号是否可以被多个进程bind?不可以,端口号指向系统中唯一的一个进程。

介绍两个小工具:

  1. pidof <进程名>:通过进程命查看进程ID,在查看服务器的进程ID时非常方便。
  2. ... | xargs proc ...:xargs可以将前面命令行中管道文件的输出转换为之后程序的命令行参数。

打一套组合拳:

在这里插入图片描述


二、UDP协议

2.1 UDP数据报格式

UDP(User Datagram Protocol,用户数据报协议)是工作在OSI(开放系统互连,Open Systems Interconnection)模型中传输层的一种协议,使用IP作为底层协议。UDP协议的格式相对简单,主要由以下几个部分组成:

在这里插入图片描述

UDP数据报分为首部和用户数据部分,整个UDP数据报作为IP数据报的数据部分封装在IP数据报中。UDP数据报文结构包括:

  • 源端口号(Source Port):占用2个字节(16位),表示发送方端口号。在要求对方回信时选用,不要求时可使用全0。
  • 目的端口号(Destination Port):占用2个字节(16位),表示接收方端口号。在终点交付报文时必须使用。
  • 长度(Length):占用2个字节(16位),表示UDP数据报的长度,包括首部和数据部分。其标定的长度最小值是8B(只有首部),最大值是2^16 = 64KB。
  • 校验和(Checksum):占用2个字节(16位),用于检测UDP数据报在传输过程中是否有错误。如果检测到校验和出错,就会直接丢弃该报文。
  • 数据(Data):占用0个或多个字节,是实际传输的数据部分。

UDP如何将报头与有效载荷进行分离?

  • UDP采用定长报头,UDP在读取报文时读取完前8个字节后剩下的就都是有效载荷

UDP如何决定将有效载荷交付给上层的哪一个协议?

  • UDP是通过报头当中的目的端口号来找到对应的应用层进程的,即由目的端口号决定。
  • 当UDP数据报到达时,操作系统会根据目的端口号找到相应的应用程序或服务,并将数据报交付给它进行处理

在Linux内核中数据报是怎样被封装和管理的?

在这里插入图片描述

  1. 首先Linux内核是使用C语言编写的,那么UDP作为传输层协议(内核中)自然也是一样。

  2. 所以UDP报头结构在内核中其实就是一个结构体类型:

    在这里插入图片描述

  3. 所以当应用程调用sendto接口发送数据时,系统就会创建并填充UDP报头。

  4. sk_buff(socket buffer)结构是linux网络代码中重要的数据结构,它负责管理和控制接收或发送数据包的信息

  5. sk_buff结构其实就是对数据报的封装,将UDP协议的报头和数据内容封装成一份完整的数据报。

  6. sk_buff结构中包含prev和next指针,操作系统将所有进程发出的sk_buff通过链表组织到一起,按序发送到网络。

  7. 对端主机将接收到的数据存入新创建的sk_buff结构当中,并依据端口号将其分派给对应进程的UDP接收缓冲区。

  8. 客户端调用recvfrom接口从UDP缓冲区读取数据,得到源端口号和报文内容。

注意:sk_buff结构较为复杂,上面的内容只是我片面的理解,甚至可能存在错误。

详情请阅读:Linux内核:sk_buff解析 - 唐稚骅 - 博客园 (cnblogs.com)


2.2 UDP协议的特点

  • 无连接:UDP在发送数据前不进行连接,发送结束时也没有连接可以释放,减少了开销和发送数据之前的时延。
  • 不可靠:没有确认机制,没有重传机制,如果因为网络故障使该段无法发送到对方,UDP协议层也不会给应用层返回任何错误信息。也正是因为UDP不保证可靠交付,使得主机不必维持复杂的连接状态。
  • 面向报文:发送方的UDP对应用程序交下来的报文,再添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。发送方发送了多少次数据报,接收方就需要接收多少次,不能一次性合并接收,也不存在接收到不完整的数据报。
  • 无拥塞控制:很多实时应用(如IP电话、实时视频会议等)要求源主机以恒定的速率发送数据,并且允许网络发生拥塞时丢失一些数据,却不允许数据有太大的时延,UDP正好适合这种要求。
  • 首部开销小:UDP只有8个字节的首部,适用于对时间敏感、但对可靠性要求不高的应用场景。
  • 全双工通信:虽然UDP没有发送缓冲区,但是UDP的socket既能读,也能写,所以也是全双工通信协议。

综上所述,UDP协议的格式简单,开销小,适用于对实时性要求较高但对可靠性要求不高的应用场景。

面向数据报

  • 应用层交付给UDP多长的报文,UDP就原样发送,既不会拆分,也不会合并,这就叫做面向数据报。

  • 可以想像成快递:你朋友给你发了1个快递,你就只能收1个快递,你不能只收0.5个快递,也不能收2个快递,你只能收1个,即发多少就收多少。

  • UDP发送的数据不能太大,UDP的报文最大长度是64KB(UDP首部+UDP数据)

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


2.3 UDP的缓冲区

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

为什么UDP没有发送缓冲区

  • 因为不需要,UDP协议的设计目标是提供一种简单的、无连接的通信方式。
  • UDP协议的设计初衷是为了实现高效的数据传输,尽量减少协议本身的开销。不提供可靠性和流量控制的机制,因此不需要发送缓冲区
  • 调用sendto会把数据直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。

为什么UDP要有接收缓冲区?

虽然 UDP 是一种无连接的、不可靠的传输协议,但仍然需要接收缓冲区来暂时存储接收到的 UDP 数据包。以下是几个理由:

  1. 数据处理速度不匹配:发送端的数据处理速度可能快于接收端的数据处理速度。如果没有接收缓冲区,接收端处理数据的速度跟不上发送端发送数据的速度,可能导致数据包在传输过程中被丢弃或溢出。通过接收缓冲区,接收端可以临时存储尚未处理的数据包,以便之后逐个处理。

  2. 数据包乱序、丢失处理:由于 UDP 协议本身不提供拥塞控制和重传机制,可能会导致数据包乱序到达或部分数据包丢失。接收缓冲区可以暂时保存乱序到达的数据包,并允许应用程序按顺序处理数据。此外,接收缓冲区还可以让应用程序检查是否丢失了某些数据包,并采取适当的措施。

  3. 简化应用程序设计:即使 UDP 是一种简单的协议,但应用程序仍需要一定的缓冲区来存储接收的数据。接收缓冲区的存在可以简化应用程序设计,让应用程序不需要关心接收时的数据处理细节,只需从缓冲区中读取数据即可。

总之,虽然 UDP 协议不提供可靠性保证,但接收缓冲区仍然是必要的,用于在一定程度上处理乱序到达、丢包等情况,并为应用程序提供一个暂存数据的地方,以便后续处理。


三、基于UDP的应用层协议

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

提示:当然, 也包括你自己写UDP程序时自定义的应用层协议。

这篇关于【传输层协议】UDP协议 {端口号的范围划分;UDP数据报格式;UDP协议的特点;UDP的缓冲区;基于UDP的应用层协议}的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096010

相关文章

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C#监听txt文档获取新数据方式

《C#监听txt文档获取新数据方式》文章介绍通过监听txt文件获取最新数据,并实现开机自启动、禁用窗口关闭按钮、阻止Ctrl+C中断及防止程序退出等功能,代码整合于主函数中,供参考学习... 目录前言一、监听txt文档增加数据二、其他功能1. 设置开机自启动2. 禁止控制台窗口关闭按钮3. 阻止Ctrl +

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

C#解析JSON数据全攻略指南

《C#解析JSON数据全攻略指南》这篇文章主要为大家详细介绍了使用C#解析JSON数据全攻略指南,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、为什么jsON是C#开发必修课?二、四步搞定网络JSON数据1. 获取数据 - HttpClient最佳实践2. 动态解析 - 快速

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I