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\n",str_add,port,buf,ret);}//关闭 套接字描述符close(sockfd);return 0;
}
代码运行结果
代码书写过程中的错误
在printf的时候 没有\n,这里和同学一起看了很久,最后在持续发送中,发现只有当缓冲区满的时候,才会输出到终端,才发现这个问题。
这里回忆一下这个知识点:
缓冲区的刷新方式
1、强制刷新
2、行刷新
3、满刷新
4、关闭刷新
重点内容:
1、端口号输出的时候,需要将网络字节序 转换为 主机字节序输出。
2、并且IP也是需要转换为字符串输出的
结束
代码重在练习!
代码重在练习!
代码重在练习!
今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!
相关文章:
Linux网络编程实战:从字节序到UDP协议栈的深度解析与开发指南
网路通信的三大要素:协议,端口和IP 知识点1【字节序】 多字节在主机中的存放数据 把多字节看成一个整体存储的顺序。 为什么我们在文件中没有这个概念呢? 因为文件是字节流(流指针),流是以一个字节为操…...
Java基础知识面试题(已整理Java面试宝典pdf版)
什么是Java Java是一门面向对象编程语言,不仅吸收了C语言的各种优点,还摒弃了C里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论…...
速盾:高防CDN访问多了会影响源站吗?
在当今数字化时代,内容分发网络(CDN)已经成为保障网站性能和用户体验的重要工具。特别是高防CDN,它不仅能够加速内容传输,还能有效抵御各种类型的网络攻击,确保业务的连续性和稳定性。然而,一些…...
Python(19)Python并发编程:深入解析多线程与多进程的差异及锁机制实战
目录 一、背景:Python并发编程的必要性二、核心概念对比2.1 技术特性对比表2.2 性能测试对比(4核CPU) 三、线程与进程的创建实战3.1 多线程基础模板3.2 多进程进阶模板 四、锁机制深度解析4.1 资源竞争问题重现4.2 线程锁解决方案4.3 进程锁的…...
赛灵思 XCVU440-2FLGA2892E XilinxFPGA Virtex UltraScale
XCVU440-2FLGA2892E 属于 Xilinx Virtex UltraScale 系列,是面向高端应用的旗舰 FPGA 器件。该系列产品以出色的高并行处理能力、丰富的逻辑资源和高速互联能力闻名,广泛用于 高性能计算、数字信号处理等对计算能力和带宽要求极高的场景。采用先进的 20n…...
UE5 相机裁剪面
UE5无法单独修改相机的裁剪面,不论是场景相机还是游戏相机都不可以 只能在配置里统一修改 项目设置里直接搜clip...
uniapp自定义底部导航栏,解决下拉时候顶部空白的问题
一、背景 最近使用uniapp开发微信小程序,因为使用了自定义的顶部导航栏,所以在ios平台上(Android未测试)测试的时候,下拉的时候会出现整个页面下拉并且顶部留下大片空白的问题 二、任务:解决这个问题 经…...
vue2 element-ui 中 el-radio 单选框点击事件失效问题
前情提要 点进这篇文章的小伙伴,应该和博主一样,都是遇到了这种单选框可点击取消的需求。也就只有这种不同寻常的需求,才能让我们发现element框架的缺陷点,话不多说,下面博主来提供一个解决思路。 click为什么无法触发…...
yolov8复现
Yolov8的复现流程主要包含环境配置、下载源码和验证环境三大步骤: 环境配置 查看电脑状况:通过任务管理器查看电脑是否有独立显卡(NVIDIA卡)。若有,后续可安装GPU版本的pytorch以加速训练;若没有࿰…...
提高Qt工作线程的运行速度
1. 使用线程池(QThreadPool)替代单一线程 做过,但是当时没想到。。。 目的:减少线程创建和销毁的开销,复用线程资源。 实现步骤: 创建自定义任务类:继承QRunnable,实现run()方法。…...
ZStack文档DevOps平台建设实践
(一)前言 对于软件产品而言,文档是不可或缺的一环。文档能帮助用户快速了解并使用软件,包括不限于特性概览、用户手册、API手册、安装部署以及场景实践教程等。由于软件与文档紧密耦合,面对业务的瞬息万变以及软件的飞…...
网络规划设计之广域网结构设计,6种架构模式对比
在数字化转型的浪潮中,网络基础设施的设计理念正在发生深刻变革。传统的基于点线拓扑的研究方法已无法满足现代复杂网络的需求,取而代之的是更具系统性的网络结构设计理念。本文将深入解析网络结构的定义特征,并重点剖析六种主流广域网架构的…...
FortiAI 重塑Fortinet Security Fabric全面智能化进阶
专注推动网络与安全融合的全球性综合网络安全解决方案供应商 Fortinet(NASDAQ:FTNT),近日宣布,旗下 Fortinet Security Fabric 安全平台成功嵌入了 FortiAI 关键创新功能。这一举措将有效增强用户对各类新兴威胁的防护…...
uniapp h5接入地图选点组件
uniapp h5接入地图选点组件 1、申请腾讯地图key2、代码接入2.1入口页面 (pages/map/map)templatescript 2.2选点页面(pages/map/mapselect/mapselect)templatescript 该内容只针对uniapp 打包h5接入地图选点组件做详细说明&#x…...
Openfein实现远程调用的方法(实操)
文章目录 环境准备一、URL中接收参数二、接收一个参数三、接收多个参数四、传递对象五、传递JSON格式数据 环境准备 下面的配置,服务调用方加入即可。 依赖导入: <!-- openfeign依赖--><dependency><groupId>org.springframe…...
Matter如何终结智能家居生态割据,重构你的居住体验?
现阶段,Zigbee、Z-Wave、Thread、Wi-Fi与蓝牙等多种通信协议在智能家居行业中已得到广泛应用,但协议间互不兼容的通信问题仍在凸显。由于各协议自成体系、彼此割据,智能家居市场被迫催生出大量桥接器、集线器及兼容性软件以在不同生态的设备间…...
Thin-Agent服务(TAS)概述
### **Thin-Agent服务(TAS)概述** **Thin-Agent服务(TAS)** 是一种轻量级监控服务,通过 **BMC/IPMI**(基板管理控制器/智能平台管理接口)收集**硬件和操作系统特定数据**,为系统管…...
2025.4.17学习日记 初识JavaScript 以及Java和JavaScript有什么区别
Java 和 JavaScript 虽然名字相似,但实际上是两种不同的编程语言。 1. 语言背景和设计目的 Java:由 Sun Microsystems(现被 Oracle 收购)在 1995 年推出。设计初衷是为了实现 “一次编写,到处运行(Write O…...
python学习—合并多个word文档
系列文章目录 python学习—合并TXT文本文件 python学习—统计嵌套文件夹内的文件数量并建立索引表格 python学习—查找指定目录下的指定类型文件 python学习—年会不能停,游戏抽签抽奖 python学习—循环语句-控制流 python学习—合并多个Excel工作簿表格文件 pytho…...
01、单片机简介
单片机简介 1、什么是单片机2、STM32F103ZET6介绍2.1、参数的含义2.2、存储器映射 3、外设寄存器介绍 1、什么是单片机 单片机(Single-Chip Microcomputer)是一种微型计算机,是一种集成电路芯片。把具有数据处理能力的中央处理器CPU、随机存储器RAM、闪存flash、多…...
常用UI设计工具及平台概览
在当今快速发展的数字世界中,UI设计平台成为设计师和开发者创建用户界面不可或缺的利器。这些平台不仅支持从简单原型到复杂交互设计的各种需求,而且许多还提供将设计直接转换为代码的功能,极大地提高了开发效率。下面将为您介绍几个主流的UI设计工具及其特点,帮助您根据项…...
考研单词笔记 2025.04.17
associate v联系,联想n同事,伙伴,朋友a副的,准的,非正式的 association n联系,联想,协会,社团,关系,交往 associative a联想的 bond n纽带,联系…...
MySQL常用SQL语句的示例
概述 MySQL 常用 SQL 语句的示例,涵盖数据定义、操作、查询等常见场景 一、数据库操作 创建数据库 CREATE DATABASE mydb;选择数据库 USE mydb;删除数据库 DROP DATABASE mydb;二、表操作 创建表 CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VAR…...
java 多线程之Worker Thread模式(Thread Pool模式)
Worker Thread模式 Worker的意思是工作的人,在Worker Thread模式中,工人线程Worker thread会逐个取回工作并进行处理,当所有工作全部完成后,工人线程会等待新的工作到来。 Worker Thread模式也被成为Background Threadÿ…...
4月17日星期四今日早报简报微语报早读
4月17日星期四,农历三月二十,早报#微语早读。 1、国家统计局:一季度国内生产总值同比增长5.4%; 2、我国博士后已超40万人,2024年招收人数再创新高; 3、神舟二十号计划近日择机实施发射,船箭组…...
【最新版】芸众商城独立版源码 425+插件 全新后台框架
一.系统介绍 芸众商城系统最新版 已经更新425全插件版,一套系统支持各种新零售、商城、模式,天天美丽链动商城。不要相信那些外面的旧版本。旧版本等于是废品,无法小程序运营的,框架还是旧的! 芸众系统最新版 服务器可…...
android liveData observeForever 与 observe对比
LiveData 是一个非常有用的组件,用于在数据变化时通知观察者。LiveData 提供了两种主要的观察方法:observe 和 observeForever。这两种方法在使用场景、生命周期感知以及内存管理等方面有所不同。 一、observe 方法 1. 基本介绍 生命周期感知:observe…...
定制化 Docsify 文档框架实战分享
🌟 定制化 Docsify 文档框架实战分享 在构建前端文档平台时,我们希望拥有更友好的用户界面、便捷的搜索、清晰的目录导航以及实用的代码复制功能。借助 Docsify,我实现了以下几个方面的定制优化,分享给大家 🙌。 &…...
蓝桥杯题目:二维前缀和
首先分析一下二维数组的差分。s[x2][y2]-s[x1][y1]s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]s[x1-1][y1-1] 因为对于二维数组x2y2-x1y1范围内的值需要通过x2y2减去从x1,y2-1的这段存储的前缀和以及减去x2-1,y1这两部分的前缀和,但是还有一个x1-1&a…...
数字孪生城市技术应用典型实践案例汇编(22个典型案例)(附下载)
近年来,数字孪生技术在我国从战略框架逐步向系统性落地推进,成为推动数字中国建设的重要技术引擎。随着《数字中国建设整体布局规划》《"十四五"数字经济发展规划》《深化智慧城市发展推进城市全域数字化转型的指导意见》等政策的实施…...
Linux——信号(1)信号的产生
我们在讲进程的多种状态时提到过,一个进程的退出有三种情况:正常退出,结果出错退出(代码也执行完了),异常终止退出(代码未执行完),其中最后一种退出相当于进程在运行时&a…...
【模型常见评价指标(分类)】
目录 常见指标 其他的评估指标 3.1 BLEU 3.2 ROUGE 3.3 困惑度PPL(perplexity) 常见指标 其他的评估指标 3.1 BLEU BLEU(Bilingual Evaluation Understudy,双语评估替补)分数是评估一种语言翻译成另一种语言的文本质量的指标。它将“质…...
个人博客系统后端 - 用户信息管理功能实现指南(上)
本文记录了如何实现用获取户信息,用户信息更新,用户头像上传三大基础功能 先上接口实现截图: 一、项目结构概览 先介绍一下 个人博客系统采用了标准的 Spring Boot 项目结构,用户功能相关的文件主要分布在以下几个目录:…...
CyberAgentAILab 开源数字人项目TANGO,heygen的开源版来了~
简介 TANGO 是 CyberAgentAILab 开源的一项前沿研究成果,其初衷在于探索高效生成模型在实际应用场景中的表现。项目诞生于 CyberAgent 在整合创意与人工智能的实践中,旨在为数字内容生成、交互和实时渲染等领域提供一个高性能、模块化、可扩展的解决方案…...
高等数学同步测试卷 同济7版 试卷部分 上 做题记录 上册期中同步测试卷 A 卷
上册期中同步测试卷A卷 一、单项选择题(本大题共5小题,每小题3分,总计15 分) 1. 2. 3. 4. 5. 二、填空题(本大题共5小题,每小题3分,总计15分) 6. 7. 8. 9. 10. 三、求解下列各题(本大题共5小题,每小题6分,总计30分) 11. …...
4.16 AT好题选做
文章目录 前言[ARC103D] Distance Sums(确定树的形态,trick)[AGC062B] Split and Insert(区间 d p dp dp)[AGC012E] Camel and Oases(状压,可行性dp转最优性dp)[ARC094D] Normalization(trick,转化)[ARC125F] Tree Degree Subset Sum(结论,a…...
数据库-day06
一、实验名称和性质 分类查询 验证 综合 设计 二、实验目的 1.掌握数据查询的Group by ; 2. 掌握聚集函数的使用方法。 三、实验的软硬件环境要求 硬件环境要求: PC机(单机) 使用的软件名称、版本号以及模块: …...
基于Flask的漏洞挖掘知识库系统设计与实现
基于Flask的漏洞挖掘知识库系统设计与实现 一、系统架构设计 1.1 整体架构 本系统采用经典的三层Web架构,通过Mermaid图展示的组件交互流程清晰呈现了以下核心模块: 前端展示层:基于Bootstrap5构建响应式界面业务逻辑层:Flask…...
小白从0学习网站搭建的关键事项和避坑指南
以下是针对小白从零学习网站搭建时需要注意的关键事项和避坑指南,帮助你高效学习、少走弯路: 一、学习路径注意事项 不要跳过基础 误区:直接学习框架(如 React、Laravel)而忽视 HTML/CSS/JS 基础。 正确做法ÿ…...
OpenAI 推出一对 AI 推理模型 o3 和 o4-mini
OpenAI 于 2025 年 4 月 16 日(美国东部时间)宣布推出两款全新的 AI 推理模型——o3 与 o4-mini,它们能够在给出最终回答前进行思考与推理。 本文中所有的 ChatGPT 服务,由 ChatShare 镜像站 提供,无需担心网络和地区限…...
知识了解03——怎么解决使用npm包下载慢的问题?
1、为什么使用npm下载包会下载的慢 因为使用npm下载包时,默认使用国外服务器进行下载,此时的网络传输需要经过漫长的海底电缆,因此下载速度会变慢 2、怎么解决?(切换镜像源) (1)方…...
【网络】IP层的重要知识
目录 1.IP层的作用 2.主机和节点 3.网络层和数据链路层的关系 4.路由控制 4.1.路由控制的过程 4.2. IP地址与路由控制 4.3.路由控制表的聚合 4.4.静态路由和动态路由 4.5.动态路由的基础 5.数据链路的抽象化 5.1.数据链路不同,MTU则相异 5.2.路径MTU发…...
【随身WIFI】随身WiFi Debian系统优化教程
0.操作前必看 本教程基于Debian系统进行优化,有些操作对随身WiFi来说可能会带来负优化,根据需要选择。 所有操作需要在root用户环境下运行,否则都要加sudo 随身wifi Debian系统,可以去某安的随声WiFi模块自行搜索刷机 点赞&am…...
IPCC指南主要变化(各版本)
1996年IPCC国家温室气体清单指南 背景:是IPCC较早发布的指南之一,为国家温室气体清单编制提供了基础方法。 内容:包括了对温室气体排放源和汇的估算方法,涵盖了能源、工业、农业等多个部门。 2006年IPCC国家温室气体清单指南 背…...
关于Diamond机械手的运动学与动力学的推导
1.关于Diamond机械手 (1)位置模型推导 逆解:机械末端平台的位置与驱动关节之间的关系。 设p点在xy平面的坐标是(x,y)T,此时根据向量求解 OP等于向量r等于e向xy轴的向量主动臂长度向xy轴的向量…...
@JsonSerialize注解自定义序列化方式
JsonSerialize注解自定义序列化方式 文章目录 JsonSerialize注解自定义序列化方式**前言****创建自定义序列化器****应用自定义序列化器****测试序列化结果****高级用法:全局注册序列化器****关键点解析****常见问题解决****问题1:序列化结果不符合预期*…...
第二篇:linux之Xshell使用及相关linux操作
第二篇:linux之Xshell使用及相关linux操作 文章目录 第二篇:linux之Xshell使用及相关linux操作一、Xshell使用1、Xshell安装2、Xshell使用 二、Bash Shell介绍与使用1、什么是Bash Shell(壳)?2、Bash Shell能干什么?3、平时如何使…...
qt中关于思源雅黑字体的使用
首先,需要下载一份思源雅黑字体,我放在了下面位置,https://download.csdn.net/download/Littlehero_121/90631851 2、关于qt中的使用操作,如下: //QString path "绝对路径";QString path QCoreApplicatio…...
用 MongoIndexStore 实现对话存档和恢复 实现“多用户、多对话线程”场景(像一个 ChatGPT 对话列表那样)
用LlamaIndex写两个完整实用的案例! 实现如何用 MongoIndexStore 实现对话存档和恢复实现“多用户、多对话线程”场景(像一个 ChatGPT 对话列表那样) ✅ 案例一:使用 MongoIndexStore 实现对话存档 恢复 单用户 单对话线程&am…...
接口测试:实用指南4.0
✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…...