Linux网络编程实战:从字节序到UDP协议栈的深度解析与开发指南
网路通信的三大要素:协议,端口和IP
知识点1【字节序】
多字节在主机中的存放数据
把多字节看成一个整体存储的顺序。
为什么我们在文件中没有这个概念呢?
因为文件是字节流(流指针),流是以一个字节为操作单位,并不是多字节
字节序分为两种:大端和小端
大端格式:高字节数据存放在低地址
小端格式:低字节数据存放在低地址

记忆方式:只看低地址,看是存储的高字节数据还是低字节数据
小(低)对小 高大上
大小端是系统决定的,我们不能更改。
Linux 都是小端的。
案例1:判断当前系统是大端还是小端
判断思路:判断低地址存放的是 低字节数据还是高字节数据
代码演示

代码运行结果:

数组是 不管是什么系统,第0个元素是低地址
知识点2【网络字节序和主机字节序】
1、如果计算机没有考虑字节序的问题,容易导致传输的数据错误
这种错误会现在异构计算机上:计算机的架构不同。小端架构和大端架构
小端主机和大端数据通信时,又有字节序的不同,导致数据错误,如下图

2、解决上述问题的方法
方法引入
我们各地都有各自的方言,为了让全国都能正常沟通,国家为此规定了普通话,将方言转换为普通话,就都能正常沟通了,普通话就是一个标准。
下图只是说明问题,并非实际过程

方法
网络 里的 数据必须是大端
因此上述的实际过程。
主机A(大端格式)传输数据,传到网络,发现是大端字节序,无需数据格式转换
主机B(小端格式)接受数据,知道网络传输的数据格式是大端格式,会进行类型格式的转换,转换为小端字节序
3、主机字节序和网络字节序
引入
那么问题又来了,主机不知道自己是什么字节序,那该如何判读是否需要数据转换呢?
因此 这里 引入和 网络字节序(net) 和主机字节序(host)
转换的过程,有需要引入两个函数
hton,ntoh:这两个函数都会进行 主机字节序 的 判断,根据判断结果决定需不需要转换。
总结
发送数据:需要将 主机字节序 转换为 网络字节序 hton
接收数据:需要将 网络字节序 转换为 主机字节序 ntoh
知识点2【字节序的转换函数】
1、主机字节序 转 网络字节序(发送)
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);//转IP
uint16_t htons(uint16_t hostshort);//转端口号
函数介绍 只介绍htonl htons类似
-
函数介绍
功能:
将 32 位主机字节序数据转换成网络字节序数据
参数:
hostint32:待转换的 32 位主机字节序数据
返回值:
成功:返回网络字节序的值
重复
端口号无符号短整型
IP地址 32位
mac地址 48位
2、网络字节序 转 主机字节序(接收)
#include <arpa/inet.h>
uint32_t ntohl(uint32_t netlong);//转ip
uint16_t ntohs(uint16_t netshort);//转端口号
-
函数介绍
功能:
将 32 位网络字节序数据转换成主机字节序数据
参数:
uint32_t: unsigned int
netint32:待转换的 32 位网络字节序数据
返回值:
成功:返回主机字节序的值
案例 htonl
代码演示
#include <stdio.h>
#include <arpa/inet.h> int main(int argc, char const *argv[])
{uint32_t num = 0x04030201;printf("num = %d\\n",num);printf("htonl(num) = %#x\\n",htonl(num));printf("htonl(num) = %d\\n",htonl(num));return 0;
}
代码运行结果

知识点3【地址转换函数】
这里的地址指的是IP地址
“10.9.11.5” 这种IP是 点分十进制串 (用户识别的IP地址)IPv4
“fe80::578a:738a:f506:f37a”这种IP是 冒分十六进制串 IPv6
但是:计算机 是用 32位无符号数据 存储的IP地址
大家判断一下 上面我写的这个字符串多少个字节
10个字节
那么 点分十进制串 最大的字节数是多少呢?
“192.168.100.101”
是16个字节(算’\0’)
因此我们以后 存储 点分十进制串 要用16个字节来存储
1、发送数据
需要将 点分十进制数串 转换为 32位无符号数
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
-
函数介绍
功能:
将点分十进制串 转换为 无符号数网络IP
参数:
af: (address family)
IPv4的点分十进制串→AF_INET
IPv6的冒分十六进制串→AF_INET6
src:输入参数,指向以空字符结尾的字符串,表示 IPv4 或 IPv6 地址。
点分十进制串 和 冒分十六进制串
dst: 输出参数,指向一个缓冲区,用于存储转换后的二进制数据。
返回值:
- 1:成功转换。
- 0:输入地址无效(例如,IPv4 字符串包含字母)。
- -1:发生错误(如
af参数不合法),可通过errno获取具体错误
代码演示
#include <stdio.h>
#include <arpa/inet.h>int main(int argc, char const *argv[])
{//实现IP 点分十进制串 向 32位IP地址(IPv4)的转换//我们假设IP地址为:10.11.1.5char *str_ip = "10.11.1.5";u_int32_t addr = 0;inet_pton(AF_INET,str_ip,&addr);printf("addr = %u\\n",addr);//现在我们按照字符遍历一下unsigned char *p = (unsigned char *)&addr;printf("%d.%d.%d.%d\\n",*p,*(p + 1),*(p + 2),*(p + 3));return 0;
}
代码运行结果

这里我自己实现了一个 pton的函数,大家看一下,有助于大家更好地理解pton
自己实现的pton
int my_pton(char *str_ip,int *addr)
{//先进性数据提取char ch_p[4];int int_p[4];sscanf(str_ip,"%d.%d.%d.%d",&int_p[0],&int_p[1],&int_p[2],&int_p[3]);//这里的数据高位(第一个%d) 存储到了&int_p[0]中,而数组下标小的在低地址,与我们想要的相反,因此我们下面要转换过来//将数据提取到字符数组当中for (size_t i = 0; i < 4; i++){if(int_p[i] > 255 || int_p[i] < 0){return 0;}ch_p[i] = (unsigned char)int_p[i];}*addr = ch_p[0] << 24 | ch_p[1] << 16 | ch_p[2] << 8 | ch_p[3];//这里不需要强转,因为会自动类型转换//现在的顺序对了,但是此时是小端存储,但是pton的结果 我们分析出 是大端存储,因此我们需要 转换为大端存储*addr = htonl(*addr);return 1;
}
代码运行结果

2、接收数据
将32为无符号数据 转换成 点分十进制数串
-
函数介绍
#include <arpa/inet.h> const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);功能:
将 二进制格式的 IP 地址 转换为 可读字符串
参数:
af:Address Family
src:输入参数,指向二进制格式的 IP 地址。
dst:输出参数,指向用于存储结果字符串的缓冲区。
size:缓冲区
dst的字节长度。需足够大以防止溢出。返回值:
- 成功:返回指向
dst的指针(即转换后的字符串地址)。 - 失败:返回
NULL,并设置errno表示具体错误。
- 成功:返回指向
知识点4【UDP编程概述】
1、socket
网络通信要解决的问题 是不同主机进程间的通信
三要素
1、IP地址
2、PORT
3、协议
socket:网络程序编程开发接口的统称
socket作用
提供不同主机上的进程之间的通信
socket特点
1、socket也称”套接字“
2、是一个特殊的文件描述符(套接字),代表一个通信管道的一个端点
3、类似对文件的操作一样,可以使用read,write,close等函数对socket套接字进行网络数据的读取和发送等操作
4、得到套接字(描述符)的方法调用socket()
5、socket可读可写,且有端口和IP
注意
不要直接成socket是文件描述符,它是一种特殊的文件描述符,它有专属名称是套接字
2、UDP的编程流

bind 绑定函数,服务器是被动的,服务器给用户一个固定的端口,而这个固定的端口的提供 需要bind绑定函数来实现,可以通过端口找到该服务器。一旦绑定了这个端口,这个端口号其他进程就不可以再使用。
绑定 客户端也是可以有的,一旦绑定,发送消息,其他客户端就知道 是本端口发送的,其他客户端也可以通过这个端口找到该客户端
客户端:创建套接字,收,发,关闭套接字
服务器:创建,绑定,收,发,关闭(图中没有,记得加上)
关闭防火墙交流
背一下:
hton:将 主机字节序 转换为 网络字节序
ntoh:将 网络字节序 转换为 主机字节序
pton:字符串转换 为 大端的二进制数据
ntop:大端二进制数据 转换为 字符串
3、socket函数创建一个套接字(通信的端点)
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int family,int type,int protocol);
功能:
创建一个用于网络通信的 socket 套接字(描述符)
参数:
family:协议族(AF_INET、AF_INET6、PF_PACKET 等)
type:套接字类(SOCK_STREAM、SOCK_DGRAM、SOCK_RAW 等)
protocol:协议类别(0、IPPROTO_TCP、IPPROTO_UDP 等
返回值:
套接字
特点:
创建套接字时,系统不会分配端口
代码演示

代码运行结果

4、IPv4地址结构体
**作用:**定义 地址结构体变量
#include <netinet/in.h>
struct in_addr
{in_addr_t s_addr;//4 字节
};struct sockaddr_in//IPv4地址 结构体
{sa_family_t sin_family;//2 字节in_port_t sin_port;//2 字节struct in_addr sin_addr;//4 字节char sin_zero[8]//8 字节
};//IPv6地址结构体 :sockaddr_in6
sin_zero 全部需要补零。作用是将结构体补充成16个字节
我们定义结构体后,建议先把结构体清零
5、通用地址结构体
对传递给函数的参数进行类型转换 不做赋值操作
struct sockaddr
{sa_family_t sa_family; // 2 字节char sa_data[14] //14 字节
};
这里解释一下,为什么要这个结构体,由family可以看出,我们可以选择IPv4 也可以选择IPv6,IPv4和IPv6是两种协议,我们在设计sendto函数的时候,由于它们所需的地址结构体是不同的,但是我们又想用同一个sendto函数。
我们就定义了一个通用地址结构体,通用结构体是16个字节,它只有前两个字节有效也就是family成员,代码中会对family就行判断,确定是IPv4 还是IPv6,然后函数内部进行结构体类型强转。就可以实现一个sendto函数完成IPv4和IPv6的通用。
综上在这里 通用地址结构体的作用类似于:**void ***
大家可以在下面sendto介绍中看一下,to 的类型是什么,还有recvform中from的的类型是什么。
6、sendto发送UDP消息
TCP消息是用send发送的。
套接字,内容,大小,0,目标,大小
#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);
功能:
向 to 结构体指针中指定的 ip,发送 UDP 数据
参数:
sockfd:套接字
buf:发送数据缓冲区
nbytes: 发送数据缓冲区的大小
flags:一般为 0
行为标志,网络数据比较复杂,紧急指针等需要特殊处理,这里我们写0就行
to:指向目的主机地址结构体的指针
addrlen:to 所指向内容的长度
返回值:
成功:发送数据的字符数
失败: -1
注意:
通过 to 和 addrlen 确定目的地址
可以发送 0 长度的 UDP 数据包
代码演示
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
int main(int argc, char const *argv[])
{//创建一个 套接字int sockfd = 0;sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){perror("socket");return 0;}printf("sockfd = %d\\n",sockfd);//遍历一下sockfd//sendto //输入数据printf("请输入数据:\\n");char buf[64] = "";fgets(buf,sizeof(buf),stdin);buf[strlen(buf) - 1] = 0;//地址结构体创建struct sockaddr_in addr;memset(&addr,0,sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(8080);inet_pton(AF_INET,"192.168.136.1",&addr.sin_addr.s_addr);//sendto 发送数据int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)(&addr),sizeof(addr));if(ret < 0){perror("sendto");return 0;}return 0;
}
代码运行结果

在上面运行结果我们看到,发送端口的端口号是随机的

这个端口是如何来的呢?
是又第一次sendto随机分配的,记住只有第一次send 才会分配,比如我们在程序中多次发送数据,在第一次sendto之后,端口号将不改变,我们将上面的代码加上循环

可以看到端口号没有改变。但是 结束该进程,开启一个新进程后,端口号会改变
但实际使用过程中,总不能端口号一直在改变,因此我们下面需要学习一下bind()函数设置固定的端口
7、bind给套接字绑定固定的 IP和端口
绑定的位置应在 socket()之后,在sendto()/recvfrom()之前
绑定函数只能绑定 本地机的IP和端口
int bind(int sockfd, const struct sockaddr *myaddr,socklen_t addrlen);
功能:
将本地协议地址 与 sockfd 绑定
参数:
sockfd: socket 套接字
myaddr: 指向特定协议的地址结构指针
addrlen:该地址结构的长度
返回值:
成功:返回 0
失败:其他
代码演示
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{//创建socketint sockfd = 0;sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){perror("socket");return 0;}printf("sockfd = %d\\n",sockfd);//固定端口 bind 套接字 地址结构体 大小struct sockaddr_in my_addr;memset(&my_addr,0,sizeof(my_addr));my_addr.sin_family = AF_INET;my_addr.sin_port = htons(8000);my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY==0,通配地址,让协议栈取本地机去找IPint ret = bind(sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr));if(ret != 0){perror("bind");return 0;}//发送消息 套接字 大小 flags 地址结构体 大小//键盘获取输入char buf[64] = "";fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;//地址结构体的配置struct sockaddr_in addr;memset(&addr,0,sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(7000);inet_pton(AF_INET,"192.168.136.1",&addr.sin_addr.s_addr);sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&addr,sizeof(addr));//关闭套接字描述符close(sockfd);return 0;
}
代码运行结果

可以看到即使是两个进程,端口号也是不变的
8、recvfrom 接收数据(带阻塞)
如果负责收数据,记得绑定固定的端口及IP
ssize_t recvfrom(int sockfd, void *buf,size_t nbytes,int flags,struct sockaddr *from,socklen_t *addrlen);
功能:
接收 UDP 数据,并将源地址信息保存在 from 指向的结构中
参数:
sockfd:套接字
buf:接收数据缓冲区
nbytes:接收数据缓冲区的大小
flags:套接字标志(常为 0)
from:源地址结构体指针,用来保存数据的来源**(可以为NULL)**
addrlen: from 的长度**(可以是NULL)**
和送礼一样,谁送的不重要,重要的是礼物
注意:
通过 from 和 addrlen 参数存放数据来源信息
from 和 addrlen 可以为 NULL, 表示不保存数据来源
返回值:
成功:接收到的字符数
失败: -1
注意:
这个返回值 我们可以利用返回值 判断数据是否收完。
接收到的数据如果小于收到的内容nybte,则表示收完了,停止接收数据。
有可能接收图片(RGB),因此我们存的话需要用unsigned char接收。
又由于以太网最大传输单元(MTU)是1500个,因此接受数组的个数1500即可
代码演示
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>int main(int argc, char const *argv[])
{//创建一个 socketint sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){perror("socket");return 0;}printf("sockfd = %d\n",sockfd);//bind 固定端口于IP 必须要进行的操作 fd,地址结构体,大小struct sockaddr_in my_addr;memset(&my_addr,0,sizeof(my_addr));my_addr.sin_family = AF_INET;my_addr.sin_port = htons(6000);my_addr.sin_addr.s_addr = htonl(INADDR_ANY);int ret = bind(sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr));if(ret != 0){perror("bind");return 0;} //接收数据while(1){unsigned char buf[1500] = "";struct sockaddr_in addr;memset(&addr,0,sizeof(addr));int addr_len = sizeof(addr);int ret = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&addr,&addr_len);if(ret < 0){perror("recvfrom");return 0;}//数据存储在buf中,数据的长度为ret//IP来源于addr.sin_addr.s_addr,需要处理//端口号为addr.sin_port,需要进行字节序转换//IP处理char str_add[16] = "";inet_ntop(AF_INET,&addr.sin_addr.s_addr,str_add,sizeof(str_add));//端口字节序转换int port = ntohs(addr.sin_port);//遍历一下printf("从IP:%s 端口号:%hu 接收到的数据为:%s,数据长度为%d",str_add,port,buf,ret);}//关闭 套接字描述符close(sockfd);return 0;
}
结束
代码重在练习!
代码重在练习!
代码重在练习!
今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!
相关文章:
Linux网络编程实战:从字节序到UDP协议栈的深度解析与开发指南
网路通信的三大要素:协议,端口和IP 知识点1【字节序】 多字节在主机中的存放数据 把多字节看成一个整体存储的顺序。 为什么我们在文件中没有这个概念呢? 因为文件是字节流(流指针),流是以一个字节为操…...
【实战篇】导入dbc文件
目录 1 前言1.1 dbc文件简介1.2 dbc文件格式规范1.2.1 基础定义部分1.2.2 网络节点定义(BU_)1.2.3 报文定义(BO_)1.2.4 信号定义(SG_)1.2.5 扩展属性与注释1.2.6 数值表(VAL_)1.2.7 环境变量(EV_)1.2.8 DBC文件的典型结构示例2 步骤2.1 打开“输入文件”窗口2.2 点击…...
合成数据在自动驾驶中的实践:工作流、关键技术与评估体系全解析
目录 合成数据在自动驾驶中的实践:工作流、关键技术与评估体系全解析 一、为什么自动驾驶离不开合成数据? 二、自动驾驶合成数据的核心使用场景 三、典型合成数据工作流(架构图建议制作成PPT) 四、评估体系:合成数…...
赋能能源 | 智慧数据,构建更高效智能的储能管理系统
行业背景 随着新能源产业的快速发展,大规模储能系统在电力调峰、调频及可再生能源消纳等领域的重要性日益凸显。 储能电站作为核心基础设施,其能量管理系统(EMS)需要处理海量实时数据,包括电池状态、功率变化、环境监…...
【音视频】音视频FLV合成实战
FFmpeg合成流程 示例本程序会⽣成⼀个合成的⾳频和视频流,并将它们编码和封装输出到输出⽂件,输出格式是根据⽂件扩展名⾃动猜测的。 示例的流程图如下所示。 ffmpeg 的 Mux 主要分为 三步操作: avformat_write_header : 写⽂件…...
猪行为视频数据集
猪行为数据集包含 23 天(超过 6 周)的日间猪行为视频,这些视频由近乎架空的摄像机拍摄。视频已配准颜色和深度信息。数据以每秒 6 帧的速度捕获,并以 1800 帧(5 分钟)为一批次进行存储。大多数帧显示 8 头猪。 这里可以看到颜色和深度图像的示例: 喂食器位于图片底部中…...
【网络技术_域名解析DNS】一、DNS 基础剖析及其原理
一、DNS 在互联网架构中的基石地位 当我们在浏览器地址栏输入www.baidu.com按下回车键的瞬间,一场跨越全球的 “数字寻址游戏” 便悄然启动。DNS(Domain Name System)作为互联网的核心基础设施,承担着将人类易读的域名转换为机…...
Java学习小册:Java并发容器与原子类
在Java并发编程中,并发容器和原子类是管理共享数据的重要工具。它们提供了线程安全的数据结构和原子操作,确保在多线程环境下数据的一致性和操作的正确性。本文将深入探讨Java中的并发容器和原子类,包括它们的基本概念、使用方法、关键类及其…...
摄影跟拍预定|基于java+vue的摄影跟拍预定管理系统(源码+数据库+文档)
摄影跟拍预定管理系统 目录 基于SprinBootvue的摄影跟拍预定管理系统 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3摄影师功能模块 4用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获…...
【HFP】深入解析蓝牙 HFP 协议中呼叫转移、呼叫建立及保持呼叫状态的机制
目录 一、核心指令概述 1.1 ATCMER:呼叫状态更新的 “总开关” 1.2 ATBIA:指示器的 “精准控制器” 1.3 指令对比 1.4 指令关系图示 二、CIEV 结果码:状态传递的 “信使” 2.1 工作机制 2.2 三类核心指示器 三、状态转移流程详解 3…...
从零开始学A2A三: A2A 能力发现与任务管理
A2A 能力发现与任务管理 学习目标 掌握智能体能力发现机制 理解 Agent Card 的结构和用途掌握能力注册和发现的流程学会管理智能体的生命周期 掌握 A2A 任务管理流程 学习任务创建和分发机制理解任务状态管理和监控掌握多智能体协作模式 理解与 MCP 的区别 对比两种架构的能…...
学习笔记十六——Rust Monad从头学
🧠 零基础也能懂的 Rust Monad:逐步拆解 三大定律通俗讲解 实战技巧 📣 第一部分:Monad 是什么? Monad 是一种“包值 链操作 保持结构”的代码模式,用来处理带上下文的值,并方便连续处理。 …...
Linux:显示 -bash-4.2$ 问题(CentOS 7)
文章目录 一、原因二、错误示例三、解决办法 一、原因 在 CentOS 7 系统中,如果你看到命令行提示符显示为 -bash-4.2$,一般是 Bash shell 正在运行,并且它没有找到用户的个人配置文件,或者这些文件有问题而未能成功加载。这个提示…...
linux共享内存通信
基础共享内存通信示例 以下示例展示生产者-消费者模型,使用共享内存传递数据: 生产者程序(producer.c) #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <string.h>#define S…...
视频监控EasyCVR视频汇聚平台接入海康监控摄像头如何配置http监听功能?
一、方案概述 本方案主要通过EasyCVR视频管理平台,实现报警信息的高效传输与实时监控。海康监控设备能通过HTTP协议将报警信息发送至指定的目的IP或域名,而EasyCVR平台则可以接收并处理这些报警信息,同时提供丰富的监控与管理功能࿰…...
代码随想录算法训练营第二十天
LeetCode题目: 39. 组合总和40. 组合总和 II131. 分割回文串2176. 统计数组中相等且可以被整除的数对(每日一题) 其他: 今日总结 往期打卡 39. 组合总和 跳转: 39. 组合总和 学习: 代码随想录公开讲解 问题: 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 targ…...
DAY09:【pytorch】nn网络层
1、卷积层 1.1 Convolution 1.1.1 卷积操作 卷积运算:卷积核在输入信号(图像)上滑动,相应位置上进行乘加卷积核:又称为滤波器、过滤器,可认为是某种模式、某种特征 1.1.2 卷积维度 一般情况下…...
大模型面试题
分布式训练相关面试题解答 什么是分布式训练? 分布式训练是一种利用多个计算节点(如多个 GPU 或多个机器)协同工作来加速训练机器学习模型的方法。它通过将训练任务分配给多个计算资源并行执行,以减少训练时间和处理大规模数据。…...
跟康师傅学Java-面向对象(基础)
跟康师傅学Java-面向对象(基础) 学习面向对象内容的三条主线(非官方) ①Java类及类的成员:(重点)属性、方法、构造器;(熟悉)代码块、内部类 ②面向对象的特征:封装、继承、多态、(抽象) ③其他关键字的使用:this、super、package、import、static、final、inte…...
2000-2017年各省国有经济煤气生产和供应业固定资产投资数据
2000-2017年各省国有经济煤气生产和供应业固定资产投资数据 1、时间:2000-2017年 2、来源:国家统计局、能源年鉴 3、指标:行政区划代码、城市、年份、国有经济煤气生产和供应业固定资产投资 4、范围:31省 5、指标说明&#x…...
线性代数 | 知识点整理 Ref 3
注:本文为 “线性代数 | 知识点整理” 相关文章合辑。 因 csdn 篇幅合并超限分篇连载,本篇为 Ref 3。 略作重排,未整理去重。 图片清晰度限于引文原状。 如有内容异常,请看原文。 《线性代数》总复习要点、公式、重要结论与重点释…...
从原理到实践:NFS复杂故障处理方法论
#作者:孙德新 文章目录 一、nfs使用概述二、疑难故障现象描述三、原理分析四、解决方案五、优化服务器资源配置:六、故障案例总结七、故障预防建议八、nfs优化方法 一、nfs使用概述 NFS(Network File System)是一种分布式文件系…...
网络层IP协议知识大梳理
全是通俗易懂的讲解,如果你本节之前的知识都掌握清楚,那就速速来看我的IP协议笔记吧~ 自己写自己的八股!让未来的自己看懂! (全文手敲,受益良多) 网路基础3 网路层 TCP并没有把数据发到网路…...
【Web前端技术】第二节—HTML标签(上)
hello!好久不见—— 做出一个属于自己的网站! 云边有个稻草人-个人主页 Web前端技术—本篇文章所属专栏 目录 一、HTML 语法规范 1.1 基本语法概述 1.2 标签关系 二、HTML 基本结构标签 2.1 第一个 HTML 网页 2.2 基本结构标签总结 三、网页开发…...
1.Axum 与 Tokio:异步编程的完美结合
摘要 深入解析 Axum 核心架构与 Tokio 异步运行时的集成,掌握关键原理与实践技巧。 一、引言 在当今的软件开发领域,高并发和高性能是衡量一个系统优劣的重要指标。对于 Web 服务器而言,能够高效地处理大量并发请求是至关重要的。Rust 语言…...
08软件测试需求分析案例-删除用户
删除用户是后台管理菜单的一个功能模块,只有admin才有删除用户的权限。不可删除admin。 1.1 通读文档 通读需求规格说明书是提取信息,提出问题,输出具有逻辑、规则、流程的业务步骤。 信息:此功能应为用户提供确认删除的功能。…...
SDL基础
SDL SDL(Simple DirectMedia Layer)是一个开源的跨平台多媒体开发库,主要用于开发需要图形、音频和输入设备支持的应用程序。它使用C语言编写,提供了简单易用的API,**能够帮助开发者快速实现跨平台的多媒体功能。**SD…...
十三种通信接口芯片——《器件手册--通信接口芯片》
目录 通信接口芯片 简述 基本功能 常见类型 应用场景 详尽阐述 1 RS485/RS422芯片 1. RS485和RS422标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6. 选型建议 2 RS232芯片 1. RS232标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6…...
反转一个字符串
用数组栈实现 void Reverse(char *C, int len) {top -1;for(int i 0; i < len; i){push(C[i]);}for(int i 0; i < len; i){C[i] Top();pop();} } 全部函数 #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAX_SIZE 101int …...
从GPT到Gemini 大模型进化史
从GPT到Gemini:大模型进化史 在过去的几年里,人工智能领域经历了翻天覆地的变化,其中最引人注目的莫过于大规模语言模型的发展。从最初的GPT系列到最近的Gemini,这些模型不仅在技术上取得了重大突破,还在实际应用中展…...
