当前位置: 首页 > news >正文

【Linux网络编程】简单的UDP网络程序

目录

一,socket编程的相关说明

1-1,sockaddr结构体

1-2,Socket API

二,基于Udp协议的简单通信


一,socket编程的相关说明

        Socket编程是一种网络通信编程技术,它允许两个或多个程序在网络上相互通信,无论这些程序是否运行在同一台计算机上。

       在Socket编程中,每个网络通信端点都被称为一个套接字(封装了底层的网络协议,如TCP/IP的细节)。这个套接字支持不同的传输协议,可以看作是两个程序之间打开的一个通信通道,通过这个通道,程序可以在网络上进行数据的传输。 

       不同主机在网络上进行数据传输时需要拿到拿到对方的端口号(标识主机的应用程序或网络服务,在网络通信中确保将数据包交给哪个主机上的应用程序来处理)和IP地址(互联网上每一台计算机的地址,在网络通信中用于标识主机的位置)。IP地址用于寻找指定机器,找到指定机器后,就需要端口号来找到指定机器下的指定服务或程序。

        注意:服务端通常不会给予特定的IP地址。首先,如果指定服务端的IP地址,那么服务端程序只能在特定的网络环境中运行,要是网络环境发生变化(例如,服务器迁移到新的IP地址),则需要重新编译和部署程序。其次,在很多的场景中,服务端程序不仅需要部署在多个服务器上,还需要在不同的机器和网络环境中运行,具有多个网络接口,它的IP地址也可能会动态变化。这时,若多个客户端连接到一个服务端上,指定特定的IP地址会导致连接出错等问题。          

1-1,sockaddr结构体

         Socket编程中,struct sockaddr 结构体是常用的类型操作,该结构体是用于描述套接字地址的通用结构体,并指定或返回网络地址信息,是一个通用的地址结构体,它通常出现在套接字函数的参数中,在网络编程中广泛使用。运用时,由于网络地址协议格式各有不同,所以该结构体通常会被更具体的地址结构体(如 struct sockaddr_in 或 struct sockaddr_in6)所替代,这些结构体提供了更详细的地址信息,需要时,一般都是通过指针将sockaddr进行强制转换,具体使用请看后面代码。

        struct sockaddr_in是基于IPv4编程的网络环境中使用的数据结构。这个结构里主要有三部分信息:地址类型、端口号、IP地址。

struct sockaddr_in

{

    地址族,对于 IPv4 来说是 AF_INET

    注意:地址族是将不同的网络层协议(如IPv4、IPv6等)进行分类的一种方式。它允许网      络设备根据地址族来识别和处理不同协议的数据包,指定源字符串的地址类型一般用          于区分IPv4和IPv6
    sa_family_t sin_family; 

    端口号,由于端口号也需要经过网络传送(网络通信时需要拿到对方的端口号进行通              信),所以传递网络前需要使用 htons()函数将其转换为网络字节序
    uint16_t sin_port;    

    包含一个 32 位IPv4 地址的结构体
    struct in_addr sin_addr;    
    用来将结构大小填充到与 struct sockaddr 相同的大小,通常被设置为零。
    char sin_zero[8];      
};

typedef uint32_t in_addr_t;

struct in_addr

{

    in_addr_t s_addr;   一个 32 位的IPv4 地址

};

注意:

      1,网络数据传输时,IP地址也需要经过网络传输,所以这里需要把点分十进制的IP地址(字符串类型)转换成网络字节序  

     2,inet_addr()用来表示一个IPv4的IP地址(32位的整数)。通常使用inet_pton()inet_addr()函数来将点分十进制的 IPv4 地址字符串转换为4字节的网络字节序(大端序)

     3,inet_pton() 和 inet_addr()虽然都是用于将IP地址(字符串形式)转换为网络字节序的二进制形式,但是,inet_pton() 不仅支持IPv4,还支持 IPv6 地址的转换,除此外,inet_pton()通常还是线程安全的(inet_addr() 可能不是线程安全的)。inet_pton() 是较新的函数,提供了更广泛的功能和更好的错误处理,但是该函数运用起来比较复杂。 

      4,当网络IP地址传送到主机上时,需要用特定的函数(比如:inet_pton())将其转换成点分十进制的字符串形式。  

inet_addr:

        格式:in_addr_t inet_addr(const char *cp);

        参数:cp:指向一个以空字符结尾的字符串,该字符串表示一个点分十进制格式的IPv4                     地址(例如,"192.168.1.1")。

        返回值:成功时,返回该IP地址的网络字节序表示(一个in_addr_t类型的值)。如果                          输入字符串不是有效的IPv4地址,函数返回INADDR_NONE(通常是-1,在                                <netinet/in.h>头文件中定义)。

inet_pton:

        格式:int inet_pton(int af, const char *src, void *dst);

        参数:

    af:地址族。一般是AF_INETAF_INET6

    src:指向一个以空字符结尾的字符串,该字符串表示一个点分十进制格式的IPv4                   地址(AF_INET)或十六进制格式的IPv6地址(AF_INET6

    dst:指向一个缓冲区,该缓冲区存储转换后的网络字节序地址

        返回值:

                成功时,返回1。

                如果输入字符串不是有效的地址格式,返回0。

                如果发生系统级错误(例如,参数不合法),返回-1。

inet_ntoa:

        功能:将网络字节序的二进制IP地址转换为点分十进制的IP地址字符串 

        格式:char *inet_ntoa(struct in_addr in); 

        参数:in:表示一个32位的IPv4地址的结构体,即需要转换网络字节序的二进制IP地址

        返回值:成功时,返回一个表示点分十进制的IP地址的字符串;失败时,返回NULL。 

1-2,Socket API

        socket API是一层抽象的网络编程接口,其中,API代表应用程序编程接口。在socket编程中,API提供了一系列用于网络通信的函数和接口。这些API函数封装了底层网络通信的复杂性,为开发者提供了简单而强大的接口。通过API,应用程序可以调用操作系统或其他软件服务提供的函数和程序,以实现特定的功能或操作。常见的socket API包括:

        1,socket。用于创建一个新的套接字,相关说明如下:

头文件:

        #include <sys/types.h>
        #include <sys/socket.h>

格式:

        int socket(int domain, int type, int protocol);

参数说明:

  • domain:指定通信时使用的协议族。常用的协议族有:
    • AF_INET:IPv4的协议族。IPv4地址类型定义在常数AF_INET中
    • AF_INET6:IPv6的协议族。IPv6地址类型定义在常数AF_INET6中
    • AF_UNIXAF_LOCAL:本地通信协议族(通常用于同一台机器上的进程间通信)。
  • type:指定套接字类型。常用的套接字类型有:
    • SOCK_STREAM:流式套接字,用于TCP连接。
    • SOCK_DGRAM:数据报套接字,用于UDP连接。
    • SOCK_RAW:原始套接字,允许对IP层及以下的数据进行直接访问和操作。
  • protocol:通常设置为0,表示自动选择该domain和type组合下的默认协议。特殊情况下会设置特定的协议,这里先不考虑。

返回值:

        成功时,该函数返回一个非负数的套接字描述符(也可以理解为文件描述符,因为Linux一切皆文件),该描述符在后续的网络操作中用于标识该套接字;失败时,返回-1。

        2,bind。函数用于将一个套接字与一个特定的地址(通常是IP地址和端口号,即sockaddr结构体)关联起来。在服务器程序中,这通常是第一步,因为服务器需要在一个特定的端口上监听来自客户端的连接请求,即绑定端口号。

      注意:在计算机网络编程中,bind 函数主要用于服务器端,而不是客户端。服务端是确定的,需要绑定到一个特定的 IP 地址和端口号,需要在应用程序启动时绑定,以便客户端能够连接到它。客户端一般可以打开多个服务(比如:打开淘宝、百度、抖音等),若是使用bind 函数连接固定的端口号,可能会导致不同的网络服务使用到同一个端口号,导致服务冲突,因此客户端通常是在首次发送数据的时候由操作系统动态分配一个临时的端口号来进行通信,不需要使用专门函数绑定到特定的 IP 地址和端口号。

头文件:

        #include <sys/types.h>
        #include <sys/socket.h>

格式:

        int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:

  • sockfd:要绑定套接字的文件描述符。
  • addr:指向一个 sockaddr 结构的指针,该结构包含了要绑定的地址和端口信息。在实际使用中,通常会使用 sockaddr_in 结构(基于IPv4地址)或 sockaddr_in6 结构(基于IPv6地址)。
  • addrlenaddr参数所指向的地址结构的长度。

返回值:

        成功时,返回0;失败时,返回-1。

         3,listen。该函数用于将套接字设置为监听状态,以接受来自客户端的连接请求。这个函数通常在服务器程序中调用,在调用 bind 函数时将套接字与特定地址(IP地址和端口号)关联之后使用。

头文件:

        #include <sys/types.h>
        #include <sys/socket.h>

格式:

        int listen(int sockfd, int backlog);

参数说明:

  • sockfd:要监听套接字的文件描述符。
  • backlog:指定系统内核应为相应套接字排队的最大连接数。一般设置为 SOMAXCONN,即使用系统定义的最大值。

返回值:

        成功时,返回0;失败时,返回-1。

        4,recvfrom。该函数用于从套接字中接收数据,默认情况下,若 recvfrom 在没有数据可读的情况下被调用它将会阻塞等待。该函数特别是在处理无连接协议(如 UDP)时经常使用。

        这里先说明下 socklen_t 类型,它是一个无符号整数类型,其长度至少为32位(具体大小可能因操作系统和平台而异),用于指定套接字地址结构的大小。

头文件:

        #include <sys/types.h>
        #include <sys/socket.h>

格式:

        ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

注意:

        ssize_t是一个平台相关的类型,在32位机器上,ssize_t通常等同于int类型;在64位机器上,它通常等同于long int类型。

参数说明:

        sockfd:套接字文件描述符,表示接收数据的套接字。

        buf:指向接收数据缓冲区的指针。

        len:指定缓冲区 buf 的大小,即最多可以接收的数据字节数。

        flags:通常设置为 0(可以是某些特性功能的字段,这里不做说明)。

        src_addr:指向 sockaddr 结构的指针,用于存储发送方地址信息。如果不需要此信息,可以设置为 NULL

        addrlen:指向一个在调用时包含 src_addr 结构大小的指针,在返回时包含实际写入 src_addr 的大小。如果 src_addr 是 NULL,则 addrlen 也应该是 NULL

返回值:

        成功时,返回接收到的字节数(如果连接已正常关闭,则返回 0);失败时,返回 -1。

        5,sendto。该函数主要用于发送数据到指定的套接字,是网络编程中发送数据的函数之一。

头文件:

        #include <sys/types.h>
        #include <sys/socket.h>

格式:

     ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

注意:

        ssize_t是一个平台相关的类型,在32位机器上,ssize_t通常等同于int类型;在64位机器上,它通常等同于long int类型。
参数说明:

  • sockfd:套接字文件描述符,表示要发送数据的套接字。
  • buf:指向包含要发送数据的缓冲区的指针。
  • len:要发送的数据的长度(以字节为单位)。
  • flags:通常设置为 0(可以是某些特性功能的字段,这里不做说明)。
  • dest_addr:指向 sockaddr 结构体的指针,表示数据发送的目标地址信息。对于 TCP 连接,这个参数通常不需要,因为连接已经建立了目标地址;但对于 UDP,这个参数是必须的。
  • addrlendest_addr 结构体的大小。

返回值:              

        成功时,返回发送的字节数;失败时,返回 -1。

        socket API还有很多,我们暂时先了解这些,后面遇到需要时会进行说明。


二,基于Udp协议的简单通信

        服务器的IP地址一般不指定,因此,下面程序实现时,我们将服务端的IP地址设为0(表示接收任意IP地址),这时只有端口号标识其服务端。

        服务端的端口号我们使用输入的环境变量的方式来确定,形式为:【可执行文件】【十六位的端口号】。其它形式的输入全部出错。这时,客户端只要连接到指定输入服务器的端口号即可完成远程网络连接进行通信。通过服务端,我们可查看客户端的IP和端口号,下面代码演示会看到。

        注意:云服务器的端口号默认都是禁止访问的,若要使用云服务器实现通信,首先需要自己开放云服务器的端口。至于如何开放云服务器的端口号请看此文章:云服务器端口开放

        客户端创建套接字时不用使用bind函数进行绑定(系统会自动绑定)。

        客户端运行的方式这里使用【可执行文件】【连接服务器的IP地址】【十六位的端口号】形式,其它形式的输入全部错误。

        程序总代码请在此链接下观看:UdpSocket代码程序

相关文章:

【Linux网络编程】简单的UDP网络程序

目录 一&#xff0c;socket编程的相关说明 1-1&#xff0c;sockaddr结构体 1-2&#xff0c;Socket API 二&#xff0c;基于Udp协议的简单通信 一&#xff0c;socket编程的相关说明 Socket编程是一种网络通信编程技术&#xff0c;它允许两个或多个程序在网络上相互通信&…...

LabVIEW中坐标排序与旋转 参见附件snippet程序

LabVIEW中坐标排序与旋转 参见附件snippet程序LabVIEW中坐标排序与旋转 参见附件snippet程序 - 北京瀚文网星科技有限公司 在LabVIEW中处理坐标排序的过程&#xff0c;尤其是按顺时针或逆时针排列坐标点&#xff0c;常见的应用包括处理几何形状、路径规划等任务。下面我将为您…...

SPIRiT-Diffusion:基于自一致性驱动的加速MRI扩散模型|文献速递-基于深度学习的病灶分割与数据超分辨率

Title 题目 SPIRiT-Diffusion: Self-Consistency Driven Diffusion Model for Accelerated MRI SPIRiT-Diffusion&#xff1a;基于自一致性驱动的加速MRI扩散模型 01 文献速递介绍 磁共振成像&#xff08;MRI&#xff09; 在临床和研究领域被广泛应用。然而&#xff0c;其…...

jwt封装教程

使用步骤&#xff1a; 1.导入jwt相关依赖 2.创建jwt工具类方便使用 3.通过工具类提供的方法进行生成jwt 4.通过工具类解析jwt令牌获取封装的数据 5.设定拦截器&#xff0c;每次执行请求的时候都需要验证token 6.注册拦截器 1.jwt依赖 <dependency><groupId>io.json…...

postman变量和脚本功能介绍

1、基本概念——global、collection、environment 在postman中&#xff0c;为了更好的管理各类变量、测试环境以及脚本等&#xff0c;创建了一些概念&#xff0c;包括&#xff1a;globals、collection、environment。其实在postman中&#xff0c;最上层还有一个Workspaces的概…...

【AI新领域应用】AlphaFold 2,原子级别精度的蛋白质3D结构预测,李沐论文精读(2021Nature封面,2024诺贝尔奖)

文章目录 AlphaFold 2 —— 原子级别精度的蛋白质3D结构预测背景&#xff08;2024诺奖与AI学习资料&#xff09;1、摘要、导论、写作技巧2、方案&#xff1a;模型&#xff0c;编码器&#xff0c;解码器3、实验&#xff1a;数据集&#xff0c;训练&#xff0c;结果 AlphaFold 2 …...

Figma汉化:提升设计效率,降低沟通成本

在UI设计领域&#xff0c;Figma因其强大的功能而广受欢迎&#xff0c;但全英文界面对于国内设计师来说是一个不小的挑战。幸运的是&#xff0c;通过Figma汉化插件&#xff0c;我们可以克服语言障碍。以下是两种获取和安装Figma汉化插件的方法&#xff0c;旨在帮助国内的UI设计师…...

前端知识点---this的用法 , this动态绑定(Javascript)

文章目录 this动态绑定 , this的用法01. 全局作用域下的 this02. 函数中的 this2.1 普通函数调用2.2 构造函数调用2.3 箭头函数中的 this 03对象方法调用04. 事件处理中的 this05. 动态绑定的方式5.1 call 方法5.2 apply 方法5.3 bind 方法 06类中的 this07. 总结 this动态绑定…...

web——upload-labs——第五关——大小写绕过绕过

先上传一个 先尝试直接上传一个普通的一句话木马 不行 可以看到&#xff0c;.htaccess文件也被过滤了&#xff0c;我们来查看一下源码 第五关的源码没有把字符强制转换为小写的语句&#xff1a; $file_ext strtolower($file_ext); //转换为小写 直接通过Burpsuite抓包修改文…...

String类型

String类 在Java中&#xff0c;String 类是一个非常核心且常用的类&#xff0c;它用于表示文本值&#xff0c;即字符序列或者说字符串。 1.1 类的声明 public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence 解释&#xff1a…...

Ubuntu24.04安装和配置Redis7.4

Ubuntu24.04安装和配置Redis7.4 #切换到root用户 sudo su -#更新源 apt update apt upgrade#安装 lsb-release、curl 和 gpg &#xff0c;以便能够添加 Redis 仓库 apt install lsb-release curl gpg#导入 Redis 的 GPG 密钥 curl -fsSL https://packages.redis.io/gpg | gpg …...

权限相关知识

1.Linux权限的概念 在说Linux权限的概念之前我来问大家一个问题&#xff0c;你们觉得什么是权限&#xff1f; 权限平时的体现呢&#xff0c;就比如不是校长的亲戚就不能逛办公室&#xff0c;没充会员的爱奇艺看不了VIP影视剧&#xff0c;没成会员的的蛋糕店拿不到会员价等等等…...

【时间之外】IT人求职和创业应知【37】-AIGC私有化

目录 新闻一&#xff1a;2024智媒体50人成都会议暨每经20周年财经媒体峰会召开 新闻二&#xff1a;全球机器学习技术大会在北京召开 新闻三&#xff1a;区块链技术在金融领域的应用取得新突破 不知不觉的坚持了1个月&#xff0c;按照心理学概念&#xff0c;还要坚持2个月&am…...

深入理解 source 和 sh、bash 的区别

1 引言 在日常使用 Linux 的过程中&#xff0c;脚本的执行是不可避免的需求之一&#xff0c;而 source、sh、bash 等命令则是执行脚本的常用方式。尽管这些命令都能运行脚本&#xff0c;但它们之间的执行方式和效果却有着显著的区别。这些区别可能会影响到脚本的环境变量、工作…...

k8clone二进制工具迁移k8s中的无状态应用

1 概述 k8clone是一个简便的Kubernetes元数据克隆工具&#xff0c;它可以将Kubernetes元数据&#xff08;对象&#xff09;保存为本地压缩包&#xff0c;在恢复时可将这些元数据恢复到目标集群中&#xff08;已存在的资源不会被覆盖&#xff09;。它不依赖远程存储&#xff0c…...

VPI photonics的一些使用经验(测相位 快速搜索)持续更新

1.使用FuncSinEl模块的注意事项&#xff1a; 2.在VPI player&#xff08;示波器&#xff09;测电信号相位时候&#xff0c;可以使用正则表达式&#xff0c;快速搜索。 比如我要搜索以30开头的数据&#xff0c;输入&#xff1a; ^30 其他的正则表达式不适用&#xff0c;比如以…...

DBeaver 连接 OceanBase Oracle 租户

DBeaver 是一款通用的数据库工具软件&#xff0c;支持任何具有JDBC驱动程序的数据库。DBeaver 需要 Java 运行环境的支持。截稿时 DBeaver 24.0.0 版本默认提供的 OceanBase 驱动是连接 MySQL 的&#xff0c;想连接 Oracle 租户需要新建一个驱动器使用。 下载数据库驱动包 1、…...

QT_CONFIG宏使用

时常在Qt代码中看到QT_CONFIG宏&#xff0c;之前以为和#define、DEFINES 差不多&#xff0c;看了定义才发现不是那么回事&#xff0c;定义如下&#xff1a; 看注释就知道了QT_CONFIG宏&#xff0c;其实是&#xff1a;实现了一个在编译时期安全检查&#xff0c;检查指定的Qt特性…...

力扣(leetcode)题目总结——辅助栈篇

leetcode 经典题分类 链表数组字符串哈希表二分法双指针滑动窗口递归/回溯动态规划二叉树辅助栈 本系列专栏&#xff1a;点击进入 leetcode题目分类 关注走一波 前言&#xff1a;本系列文章初衷是为了按类别整理出力扣&#xff08;leetcode&#xff09;最经典题目&#xff0c…...

如何处理 iOS 客户端内 Webview H5 中后台播放的音视频问题

目录 问题描述Page Visibility API 的应用什么是 Page Visibility API&#xff1f;使用 Page Visibility API 暂停音视频完整解决方案1. 监听媒体的播放和暂停事件2. 防止自动播放3. 结合 Intersection Observer 进行媒体控制4. 手动处理应用生命周期中的事件 问题描述 在 iOS…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...