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

14 地址映射

14 地址映射

  • 1、地址划分
  • 2、相关函数
    • 2.1 ioremap/iounmap
    • 2.2 mmap地址映射
  • 3、总结

1、地址划分

  • 明确:在linux系统中,不管是应用程序还是驱动程序,都不允许直接访问外设的物理地址,要想访问必须将物理地址映射到用户虚拟地址或者内核虚拟地址,一旦映射完毕,应用或者内核程序访问映射的虚拟地址,就是在访问实际的物理地址
  • 在linux系统中,4G虚拟地址空间的划分
    用户虚拟地址范围:0x00000000~0xBFFFFFFF
    内核虚拟地址范围:0xC0000000~0xFFFFFFFF
  • 如何将物理地址映射到内核虚拟地址?- 利用ioremap函数
  • 如何将物理地址映射到用户虚拟地址?- 利用mmap
  • 一个物理地址可以有多个虚拟地址,一个虚拟地址不能有多个物理地址

2、相关函数

2.1 ioremap/iounmap

void *ioremap(unsigned long phy_address, unsigned long len)
- 功能:将物理地址映射到内核虚拟地址
- 参数:- phy_address:传递要映射的起始的物理地址- len:传递要映射的物理地址空间的大小
- 返回值:返回映射的起始内核虚拟地址
void iounmap(void *vir_address)
- 功能:解除物理地址和内核虚拟地址的映射关系
- 参数:vir_address:传递映射好的起始内核虚拟地址
  • 案例:使用地址映射操作gpio
  寄存器     		  物理地址		 内核虚拟地址 
GPIOCALTFN0			0xC001C020		  gpiocaltfn0
GPIOCOUTENB			0xC001C004		  gpiocoutenb
GPIOCOUTENB			0xC001C000		  gpiocout 
//地址映射,两种方案:
方案1unsigned long *gpiocout, *gpiocoutenb, *gpiocaltfn0;gpiocout = ioremap(0xC001C000, 4);gpiocoutenb = ioremap(0xC001C004, 4);gpiocaltfn0 = ioremap(0xC001C020, 4);方案2:由于寄存器的物理地址空间都是连续的,所以连续映射:void *gpiobase;unsigned long *gpiocout, *gpiocoutenb, *gpiocaltfn0;gpiobase = ioremap(0xC001C000, 0x24);//地址换算gpiocout = (unsigned long *)(gpiobase + 0x00);gpiocoutenb = (unsigned long *)(gpiobase + 0x04);gpiocaltfn0 = (unsigned long *)(gpiobase + 0x20);//配置模式
*gpiocaltfn0 &= ~(3 << 24);
*gpiocaltfn0 |= (1 << 24);//使能
*gpiocoutenb |= (1 << 12);//输出
*gpiocout |= (1 << 12);
*gpiocout &= ~(1 << 12);

案例:实现一个软件能够编辑处理器任意一个寄存器
驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/io.h> //ioremap/iounmap
#include <linux/uaccess.h>
//描述寄存器操作信息的结构体
struct reg_info {unsigned long phy_address; //寄存器物理地址unsigned long data;		   //寄存器数据
};#define REG_WRITE 	0x100001 	//写寄存器命令
#define REG_READ	0x100002	//读寄存器命令
static long reg_ioctl(struct file *file,unsigned int cmd,unsigned long buf) {unsigned long *gpiobase;struct reg_info kreg;copy_from_user(&kreg,(struct reg_info *)buf,sizeof(kreg));//结果:kreg.phy_address=物理地址,kreg.data=?//将寄存器物理地址映射到内核虚拟地址gpiobase = ioremap(kreg.phy_address, 4);if(gpiobase == NULL) {printk("ioremap failed.\n");return -1;}switch(cmd) {case REG_WRITE:*gpiobase = kreg.data;break;case REG_READ:kreg.data = *gpiobase;copy_to_user((struct reg_info *)buf,&kreg, sizeof(kreg));break;}//解除地址映射iounmap(gpiobase);return 0;
}
static struct file_operations reg_fops = {.unlocked_ioctl = reg_ioctl
};
static struct miscdevice reg_misc = {.name = "reg",.minor = MISC_DYNAMIC_MINOR,.fops = &reg_fops
};
static int reg_init(void) {misc_register(&reg_misc);return 0;
};
static void reg_exit(void){misc_deregister(&reg_misc);
};module_init(reg_init);
module_exit(reg_exit);
MODULE_LICENSE("GPL");

应用程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct reg_info {unsigned long phy_address; //寄存器物理地址unsigned long data;		   //寄存器数据
};
#define REG_WRITE	0x100001	//写寄存器命令
#define REG_READ	0x100002	//读寄存器命令
int main(int argc, char *argv[]) {int fd;struct reg_info reg; //暂存寄存器的操作信息if((argc != 3) && (argc != 4)) {printf("Usage: %s w address data\n", argv[0]);printf("%s r address\n", argv[0]);return -1;}fd = open("/dev/reg", O_RDWR);if(fd < 0) {printf("open reg test device failed.\n");return -1;}if(!strcmp(argv[1], "w")) {reg.phy_address = strtoul(argv[2], NULL, 0);reg.data = strtoul(argv[3], NULL, 0);ioctl(fd, REG_WRITE, &reg);} else if(!strcmp(argv[1], "r")) {reg.phy_address = strtoul(argv[2], NULL, 0);ioctl(fd, REG_READ, &reg);printf("%#x:%#x\n",reg.phy_address, reg.data);}close(fd);return 0;
}

测试

./btn_test w 0xC001C000 0xC84 # 开灯
./btn_test w 0xC001C000 0x1C84 # 关灯
  • 字符串转整形标准C库函数:strtoul
unsigned long strtoul(char *pstr, char **ppstr, int n);
- 功能:字符串转整形,例如:"100"->100, "0100"->0100, "0x100"->0x100 
- 参数: - pstr: 传递转换的字符串首地址- ppstr:记录字符串中非整形数的子字符串首地址- n:指定转换进制
- 返回值:返回转换的整形数例如: 
char *pstr = "100";
int a = strtoul(pstr, NULL, 0); //结果:a=100
char *pstr = "0100";
int a = strtoul(pstr, NULL, 0); //结果:a=0100
char *pstr = "0x100";
int a = strtoul(pstr, NULL, 0); //结果:a=0x100
char *pstr = "100";
int a = strtoul(pstr, NULL, 16); //结果:a=0x64
char *pstr = "100abcd";
char *pstr1 = NULL; 
int a = strtoul(pstr, &pstr1, 0); //结果:a=100,pstr1 = "abcd"

2.2 mmap地址映射

mmap就是完成物理地址映射到用户虚拟地址用的

用户3G虚拟地址空间划分:
0x00000000-------------------------------------------------------0xBFFFFFFF代码段  数据段  BSS段  堆区   MMAP虚拟内存区      栈区---->  <------       <----

系统调用函数原型:

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
- 功能:将物理地址空间映射到用户虚拟内存空间上			  
- 参数:- addr:NULL,让linux内核帮你在用户虚拟内存区域找一块空间内存用来映射物理地址- length:让linux内核帮你找空闲用户虚拟内存的大小;切记:大小必须是页面大小(4KB)的整数倍- prot:描述内核帮你找的空闲用户虚拟内存的访问权限一般指定为:PROT_READ|PROT_WRITE- flags:其余属性,一般指定为:MAP_SHARED- fd:硬件外设- offset:偏移量,一般给0
- 返回值:linux内核将空闲的用户虚拟内存的首地址进行返回,这个起始用户虚拟地址同样也是4KB整数倍

参考代码:

void *addr;
int fd = open("a.txt", O_RDWR);
addr = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0);
说明:将文件a.txt映射到以addr起始的用户虚拟内存上,将来访问映射的用户虚拟内存就是访问文件
//向映射的用户虚拟内存拷贝字符串数据
本质是向文件a.txt写入数据
memcpy(addr, "hello,world", 12);
  • 了解mmap系统调用函数所做的工作:
    1. 应用程序调用mmap,首先跑到C库的mmap函数定义
    2. C库的mmap函数作两件事:
      1.保存mmap系统调用号到r7寄存器
      2.调用swi/svc指令触发软中断异常
    3. 一旦触发软中断异常,CPU核立马处理软中断异常
      CPU核硬件自动做四件事:…
      软件进一步处理软中断异常(在内核空间完成)
    4. 最后进程跑到内核空间继续运行,跑到软中断异常的入口地址运行,做三件事:
      1.保护现场
      2.调用软中断异常处理函数,而此函数又做两件事:
      1.从r7寄存器中取出mmap系统调用号
      2.以mmap系统调用号为下标在内核的系统调用表中找到mmap对应的内核函数sys_mmap,而内核的sys_mmap做三件事:
      1. 内核的sys_mmap首先在当前进程的3G虚拟地址空间中找一块空闲的用户虚拟内存,将来用于和物理地址做映射
      2. 一旦找到空闲的用户虚拟内存,并且用户mmap本身也给用户虚拟内存指定了一堆的属性(大小,权限等)所以内核用struct vm_area_struct数据结构定义初始化一个对象来描述空闲的用户虚拟内存的属性
      3. 最后内核的sys_mmap调用底层驱动的mmap接口,并且内核sys_mmap将第2步创建的对象的地址也传递给底层驱动的mmap接口
      3.底层驱动mmap执行完毕,然后恢复现场状态恢复和跳转返回,至此mmap调用结束

struct vm_area_struct {
unsigned long vm_start; //空间用户虚拟内存的起始地址 等于mmap的返回值addr
unsigned long vm_end; //结束地址=vm_start+大小
pgprot_t vm_page_prot; //等于mmap传递的PROT_READ|PROT_READ|PROT_WRITE
unsigned long vm_flags; //等于mmap传递的MAP_SHARED
unsigned long vm_pgoff; //等于mmap传递的0

};

3.对应的底层驱动的mmap接口
```c
struct file_operations {int (*mmap) (struct file *file, struct vm_area_struct *vma);
};
- 功能:永远只能唯一做一件事:将已知的物理地址和已知的用户虚拟地址做映射,由于用户虚拟地址在用户空间,所以将来访问操作都是在应用程序完成,而不是在内核驱动完成,访问映射的用户虚拟地址就是在访问物理地址
- file:跟fd亲戚关系
- vma:指向内核sys_mmap创建的一个对象,此对象来描述空闲的用户虚拟内存的各种属性,将来底层驱动mmap接口利用此指针可以获取到用户虚拟内存的属性:vma->vm_start //获取起始用户虚拟地址vma->vm_end vma->vm_flagsvma->vm_page_prot

问:底层驱动的mmap接口到底如何最终完成映射呢?
因为已知物理地址可以看手册获取到,已知的用户虚拟地址通过vma指针能够获取到如何将两者关联在一起呢?
答:只需调用以下函数完成关联映射:

int remap_pfn_range(struct vm_area_struct *vma,unsigned long addr,unsigned long pfn, unsigned long size,pgprot_t prot);
- 功能:完成最终的地址映射
- 参数:- vma:传递内核sys_mmap创建的对象地址,也就是传递驱动mmap接口的第二个参数- addr:传递空闲的用户虚拟内存的首地址,也就是传递vma->vm_start- pfn:传递起始的物理地址>>12 切记:此物理地址大小必须是4KB(0x1000)整数倍例如:0xC001C000>>12:合法0xC001C004>>12:不合法- size:传递映射的用户虚拟内存的大小,也就是传递:vma->vm_end - vma->vm_start - prot:传递用户虚拟内存的访问权限,也就是传递:vma->vm_page_prot

案例:利用mmap实现开关灯操作
驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/mm.h>static int btn_mmap(struct file *file,struct vm_area_struct *vma){remap_pfn_range(vma,// 指向用户虚拟内存属性vma->vm_start,// 起始用户虚拟地址0xC001C000 >> 12,// 起始物理地址 (4KB为单位)vma->vm_end - vma->vm_start,// 大小vma->vm_page_prot // 读写访问权限);return 0;
}static struct file_operations btn_fops = {.mmap = btn_mmap // 地址映射接口
};static struct miscdevice btn_device={.name = "mybtn",.minor = MISC_DYNAMIC_MINOR,.fops = &btn_fops
};
static int btn_init(void){misc_register(&btn_device);return 0;
}
static void btn_exit(void){misc_deregister(&btn_device);
}module_init(btn_init);
module_exit(btn_exit);
MODULE_LICENSE("GPL");

应用程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc,char *argv[]){int fd;void* gpiobase;unsigned long *gpiocout;unsigned long *gpiocoutend;unsigned long *gpiocaltfn0;fd = open("/dev/mybtn",O_RDWR);if(fd<0){printf("open mybtn failed\n");return -1;}//将内核地址映射到用户虚拟地址gpiobase = mmap(NULL,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);// 地址换算gpiocout = (unsigned long *)(gpiobase + 0x00);gpiocoutend = (unsigned long *)(gpiobase + 0x04);gpiocaltfn0 = (unsigned long *)(gpiobase + 0x20);// 配置输出*gpiocaltfn0 &=~(3<<24);*gpiocaltfn0 |=(1<<24);// 使能*gpiocoutend |=(1<<12);// 输出为1*gpiocout |=(1<<12);while(1){*gpiocout |=(1<<12);sleep(5);*gpiocout &=~(1<<12);sleep(5);}
}

注意,如果出现了操作了寄存器,但是硬件不同步的现象,需要手动关闭cache功能

static int btn_mmap(struct file *file,struct vm_area_struct *vma){// 关闭cache功能vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);remap_pfn_range(vma,// 指向用户虚拟内存属性vma->vm_start,// 起始用户虚拟地址0xC001C000 >> 12,// 起始物理地址 (4KB为单位)vma->vm_end - vma->vm_start,// 大小vma->vm_page_prot // 读写访问权限);return 0;
}

3、总结

read,write,ioctl和mmap对比
什么时候用:read,write,ioctl,什么时候用: mmap

  • read,write,ioctl数据操作流程
    对设备读操作:read,ioctl
    数据流:硬件寄存器----->内核缓冲区------->用户缓冲区
    gpio_get_value copy_to_user
    对设备写操作:write,ioctl
    数据流:用户缓冲区----->内核缓冲区------->硬件寄存器
    copy_from_user gpio_set_value
    结论:read,write,ioctl数据操作势必要经过两次数据拷贝:
    用户-内核->硬件
    硬件->内核->用户

  • mmap数据操作流程:
    对设备读操作: 应用程序直接以指针形式读取寄存器
    data = *gpiocout;
    对设备写操作: 应用程序直接以指针的形式写入寄存器
    *gpiocout &= ~(1 << 12);
    结论:mmap数据操作只需一个数据拷贝:
    用户->硬件
    硬件->用户

  • 所以:

    1. 如果用户对硬件操作访问的数据量比较小,read,write,ioctl的两次数据拷贝对系统性能肯定有影响,但是这种影响几乎可以忽略不计,如果操作的数据量比较大,两次数据拷贝性能的影响是致命的,例如:摄像头,LCD显示屏,声卡等
    2. 如果访问操作的数据量比较大,用read,write,ioctl势必影响系统的性能,务必采用mmap,将两次数据拷贝变成一次提供系统的性能效率
    3. 由于mmap在使用的时候,分配的用户虚拟内存必须是4KB的整数倍,如果操作的数据量比较小,此时还用mmap即使提高了系统的性能(几乎体会不到),反而是浪费了宝贵的内存资源

相关文章:

14 地址映射

14 地址映射 1、地址划分2、相关函数2.1 ioremap/iounmap2.2 mmap地址映射 3、总结 1、地址划分 明确&#xff1a;在linux系统中,不管是应用程序还是驱动程序&#xff0c;都不允许直接访问外设的物理地址,要想访问必须将物理地址映射到用户虚拟地址或者内核虚拟地址&#xff0…...

Java Resilience4j-RateLimiter学习

一. 介绍 Resilience4j-RateLimiter 是 Resilience4j 中的一个限流模块&#xff0c;我们对 Resilience4j 的 CircuitBreaker、Retry 已经有了一定的了解&#xff0c;现在来学习 RateLimiter 限流器&#xff1b; 引入依赖&#xff1b; <dependency><groupId>io.g…...

Nginx--地址重写Rewrite

一、什么是Rewrite Rewrite对称URL Rewrite&#xff0c;即URL重写&#xff0c;就是把传入Web的请求重定向到其他URL的过程 URL Rewrite最常见的应用是URL伪静态化&#xff0c;是将动态页面显示为静态页面方式的一种技术。比如http://www.123.com/news/index.php?id123 使用U…...

webflux源码解析(1)-主流程

目录 1.关键实例的创建1.1 实例创建1.2 初始化 2.处理请求的关键流程2.1 从ReactorHttpHandlerAdapter开始2.1 DispatcherHandler的初始化2.2查找mapping handler2.3 处理请求(执行handler)2.4 返回结果处理 3.webflux的配置装配参考&#xff1a; WebFlux是Spring 5.0框架推出的…...

ipad作为扩展屏的最简单方式

将iPad用作扩展屏幕有几种简单而有效的方法。以下是几种常见的方式&#xff1a; 1. Sidecar&#xff08;苹果官方功能&#xff09; 适用设备&#xff1a;iPad和Mac&#xff08;macOS Catalina及以上版本&#xff09;。功能&#xff1a;Sidecar 是苹果官方的功能&#xff0c;可…...

【卡码网Python基础课 17.判断集合成员】

目录 题目描述与分析一、集合二、集合的常用方法三、代码编写 题目描述与分析 题目描述&#xff1a; 请你编写一个程序&#xff0c;判断给定的整数 n 是否存在于给定的集合中。 输入描述&#xff1a; 有多组测试数据&#xff0c;第一行有一个整数 k&#xff0c;代表有 k 组测…...

生物研究新范式!AI语言模型在生物研究中的应用

–https://doi.org/10.1038/s41592-024-02354-y 留意更多内容&#xff0c;欢迎关注微信公众号&#xff1a;组学之心 Language models for biological research: a primer 研究团队及研究单位 James Zou–Department of Biomedical Data Science, Stanford University, Stan…...

python语言day08 属性装饰器和property函数 异常关键字 约束

属性装饰器&#xff1a; 三个装饰器实现对私有化属性_creat_time的get&#xff0c;set&#xff0c;del方法&#xff1b; 三个装饰器下的方法名都一样&#xff0c;通过message.creat_time的不同操作实现调用get&#xff0c;set&#xff0c;del方法。 __inti__&#xff1a; 创建并…...

day01JS-数据类型-01

1. 浏览器内核 通常所谓的浏览器内核也就是浏览器所采用的渲染引擎&#xff0c;渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解释也有不同&#xff0c;因此同一网页在不同的内核的浏览器里的渲染&#xff08;显示&#xff09;…...

MATLAB 手动实现一种高度覆盖值提取建筑物点云的方法(74)

专栏往期文章,包含本章 MATLAB 手动实现一种高度覆盖值提取建筑物点云的方法(74) 一、算法介绍二、算法实现1.代码2.效果总结一、算法介绍 手动实现一种基于高度覆盖值的建筑物点云提取方法,适用于高大的城市建筑物,比只利用高度提取建筑物的方法更加稳定和具有价值,主要…...

git的下载与安装(Windows)

Git是一个开源的分布式版本控制系统&#xff08;Distributed Version Control System&#xff0c;简称DVCS&#xff09;&#xff0c;它以其高效、灵活和强大的功能&#xff0c;在现代软件开发中扮演着至关重要的角色。 git官网&#xff1a;Git (git-scm.com) 1.进入git官网 2…...

腾讯云AI代码助手 —— 编程新体验,智能编码新纪元

阅读导航 引言一、开发环境介绍1. 支持的编程语言2. 支持的集成开发环境&#xff08;IDE&#xff09; 二、腾讯云AI代码助手使用实例1. 开发环境配置2. 代码补全功能使用&#x1f4bb;自动生成单句代码&#x1f4bb;自动生成整个代码块 3. 技术对话3. 规范/修复错误代码4. 智能…...

使用 ESP32 和 TFT 屏幕显示实时天气信息 —— 基于 OpenWeatherMap API

实时监测环境数据是一个非常常见的应用场景&#xff0c;例如气象站、智能家居等。这篇博客将带你使用 ESP32 微控制器和一个 TFT 屏幕&#xff0c;实时显示当前城市的天气信息。通过 OpenWeatherMap API&#xff0c;我们能够获取诸如温度、天气情况以及经纬度等详细的天气数据&…...

高阶数据结构——B树

1. 常见的搜索结构 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有100G数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了&#xff0c;如果放在磁盘上&#xff0…...

Vue2中watch与Vue3中watch对比和踩坑

上一节说到了 computed计算属性对比 &#xff0c;虽然计算属性在大多数情况下更合适&#xff0c;但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法&#xff0c;来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时&#…...

在Java程序中执行Linux命令

在Java中执行Linux命令通常涉及到使用Java的运行时类 (java.lang.Runtime) 或者 ProcessBuilder 类来启动一个外部进程 1. 使用 Runtime.exec() Runtime.exec() 方法可以用来执行一个外部程序。它返回一个 Process 对象&#xff0c;可以通过这个对象与外部程序交互&#xff0…...

微信小程序在不同移动设备上的差异导致原因

在写小程序的时候用了rpx自适应单位&#xff0c;但是还是出现了在不同机型上布局不统一的问题&#xff0c;在此记录一下在首页做一个输入框&#xff0c;在测试的时候&#xff0c;这个输入框在不同的机型上到处跑&#xff0c;后来排查了很久都不知道为什么会这样 解决办法是后 …...

快速体验fastllm安装部署并支持AMD ROCm推理加速

序言 fastllm是纯c实现&#xff0c;无第三方依赖的高性能大模型推理库。 本文以国产海光DCU为例&#xff0c;在AMD ROCm平台下编译部署fastllm以实现LLMs模型推理加速。 测试平台&#xff1a;曙光超算互联网平台SCNet GPU/DCU&#xff1a;异构加速卡AI 显存64GB PCIE&#…...

报错:java: javacTask: 源发行版 8 需要目标发行版 1.8

程序报错&#xff1a; Executing pre-compile tasks... Loading Ant configuration... Running Ant tasks... Running before tasks Checking sources Copying resources... [gulimail-coupon] Copying resources... [gulimail-common] Parsing java… [gulimail-common] java…...

【数据结构篇】~单链表(附源码)

【数据结构篇】~链表 链表前言链表的实现1.头文件2.源文件 链表前言 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 1、链式机构在逻辑上是连续的&#xff0c;在物理结构上不一定连续​ 2、结点一般是从…...

旋转图像(LeetCode)

题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 解题 def rotate(matrix):n len(matrix)# 矩阵转置for i in range(n):for…...

入门 - vue中v-model的实现原理和完整用法详解

v-model介绍 v-model是vue的双向绑定的指令&#xff0c;能将页面上控件输入的值同步更新到相关绑定的data属性&#xff0c;也会在更新data绑定属性时候&#xff0c;更新页面上输入控件的值。在view层&#xff0c;model层相互需要数据交互&#xff0c;即可使用v-model。 双向绑…...

【区块链+金融服务】港融区域股权服务平台 | FISCO BCOS应用案例

中国证监会在 2020 年启动了区块链建设试点工作&#xff0c;提出建设基于区块链的场外市场登记系统和交易报告库&#xff0c;利 用区块链去中心化、不易篡改、安全稳定等技术特点&#xff0c;构建区域性股权市场数字化信任机制&#xff0c;为区域性股权市场 提供基础支撑设施。…...

Nginx反向代理和前后端分离项目打包部署

Nginx反向代理 Nginx的定位&#xff1a;主要用于做反向代理&#xff0c;一般都是用它来做前端页面的服务器&#xff0c;动态资源代理到后端服务器。这样做的好处是可以避免跨域请求带来的不便。 使用Nginx主要是对Nginx中的nginx.conf文件进行配置&#xff1a; 虚拟主机配置…...

Spring 中ApplicationContext

ApplicationContext 是 Spring 框架中最重要的接口之一&#xff0c;用于提供 Spring IoC 容器的功能。它是一个比 BeanFactory 更高级的容器&#xff0c;负责管理 Spring bean 的生命周期&#xff0c;同时提供对各种企业服务的集成&#xff0c;例如事件传播、国际化、弱引用等。…...

python之时间 datetime、date、time、timedelta、dateutil

在 Python 中&#xff0c;处理日期和时间的常用库是 datetime。此外&#xff0c;还有一些第三方库如 pytz 和 dateutil 可以帮助处理时区和日期解析。 1. 使用 datetime 模块 导入模块 from datetime import datetime, date, time, timedelta获取当前日期和时间 now datet…...

【机器学习第11章——特征选择与稀疏学习】

机器学习第11章——特征选择与稀疏学习 11.特征选择与稀疏学习11.1子集搜索与评价子集搜索子集评价 11.2 过滤式选择11.3 包裹式选择11.4 嵌入式选择11.5 稀疏表示与字典学习稀疏表示字典学习 11.6 压缩感知 11.特征选择与稀疏学习 11.1子集搜索与评价 特征&#xff1a;描述物…...

LeetCode-day43-3137. K 周期字符串需要的最少操作次数

LeetCode-day43-3137. K 周期字符串需要的最少操作次数 题目描述示例示例1&#xff1a;示例2&#xff1a; 思路代码 题目描述 给你一个长度为 n 的字符串 word 和一个整数 k &#xff0c;其中 k 是 n 的因数。 在一次操作中&#xff0c;你可以选择任意两个下标 i 和 j&#x…...

基于springboot的智能家居系统

TOC springboot198基于springboot的智能家居系统 研究背景与现状 时代的进步使人们的生活实现了部分自动化&#xff0c;由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现&#xff0c;都为人们生活的享受提供帮助。采用新型的自动化方式…...

【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(七)

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…...

C:每日一练:单身狗(2.0版本)

前言&#xff1a; 今天在刷题的时候突然看到一道题&#xff0c;疑似一位故题。仔细一看&#xff0c;欸&#xff01;这不是就是单身狗的升级版吗&#xff1f;我想那必须再安排一篇&#xff0c;不过由于本篇文章与上一篇单身狗文章所涉及的知识点基本相同&#xff0c;所以还请大…...

打破接口壁垒:适配器模式让系统无缝对接

适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许不兼容的接口之间协同工作。主要用途是将一个类的接口转换成客户期望的另一个接口&#xff0c;使得原本接口不兼容的对象可以一起工作。 一、适配器模式的组成 目标接口&#xff08…...

U-Boot 命令使用

U-Boot 是一种常用的引导加载程序&#xff0c;用于引导嵌入式系统。它提供了一系列命令以进行系统配置、引导操作和调试。 以下是一些常见的 U-Boot 命令及其用法&#xff1a; bootm&#xff1a;从指定的内存地址启动操作系统映像。 用法&#xff1a;bootm [addr] bootz&…...

谷歌的高级指令有哪些

今天会分享一些组合用法&#xff0c;这样就能节省许多时间可以放在跟进客户上面&#xff08;本文只介绍谷歌的搜索指令&#xff0c;并无推广&#xff09; part one 谷歌常用的搜索引擎指令&#xff1a; 1、Inurl&#xff0c;在网址中 2、Intext&#xff0c;在网页内容中 3、…...

Redis操作--RedisTemplate(一)介绍

一、介绍 1、简介 RedisTemplate 是 Spring Data Redis 提供的一个高级抽象&#xff0c;由 Spring 官方提供的方便操作 Redis 数据库的一个工具类&#xff0c;支持模板设计模式&#xff0c;使得操作 Redis 更加符合 Spring 的编程模型。还支持序列化机制&#xff0c;可以处理…...

GitLab环境搭建

GitLab环境搭建 一、环境搭建 1、更新系统软件包: sudo yum update2、安装docker sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install do…...

Socket编程TCP 基础

一.什么是Socket(套接字&#xff09; 定义&#xff1a;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲&#xff0c;套接字上联应用进程&#x…...

JAVA中的Iterator与ListIterator

Java中的Iterator类是Java集合框架中的一个重要接口&#xff0c;它用于遍历集合中的元素。Iterator提供了三个基本操作&#xff1a;检查是否有下一个元素、获取下一个元素以及移除元素。下面将详细介绍Iterator类及其使用方法&#xff0c;并提供相应的代码例子和中文注释。 一、…...

高校疫情防控web系统pf

TOC springboot365高校疫情防控web系统pf 第1章 绪论 1.1 课题背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。所以各行…...

复现nnUNet2并跑通自定义数据

复现nnUNet2并跑通自定义数据 1. 配置环境2. 处理数据集2.1 创建文件夹2.2 数据集格式转换2.3 数据集预处理 3. 训练4. 改进模型4.1 概要4.2 加注意力模块 1. 配置环境 stage1&#xff1a;创建python环境&#xff0c;这里建议python3.10 conda create --n nnunet python3.10 …...

Educational Codeforces Round 169 (Rated for Div. 2)(ABCDE)

A. Closest Point 签到 #define _rep(i,a,b) for(int i(a);i<(b);i) int n,m; int q[N]; void solve() {cin>>n;_rep(i,1,n)cin>>q[i];if(n!2)cout<<"NO\n";else if(abs(q[1]-q[2])!1)cout<<"YES\n";else cout<<"…...

成为Python砖家(2): str 最常用的8大方法

str 类最常用的8个方法 str.lower()str.upper()str.split(sepNone, maxsplit-1)str.count(sub[, start[, end]])str.replace(old, new[, count])str.center(width[, fillchar])str.strip([chars])str.join(iterable) 查询方法的文档 根据 成为Python砖家(1): 在本地查询Pyth…...

深入理解JVM运行时数据区(内存布局 )5大部分 | 异常讨论

前言&#xff1a; JVM运行时数据区&#xff08;内存布局&#xff09;是Java程序执行时用于存储各种数据的内存区域。这些区域在JVM启动时被创建&#xff0c;并在JVM关闭时销毁。它们的布局和管理方式对Java程序的性能和稳定性有着重要影响。 目录 一、由以下5大部分组成 1.…...

JAVA根据表名获取Oracle表结构信息

响应实体封装 import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor;/*** author CQY* version 1.0* date 2024/8/15 16:33**/ Data NoArgsConstructor AllArgsConstructor Builder public class OracleTableInfo …...

网络性能优化

网络性能优化是确保网络稳定性、速度和可靠性的关键步骤。优化过程通常包括诊断问题、识别瓶颈以及实施具体的解决方案。以下是关于如何进行网络性能优化的详细指南&#xff1a; 一、问题诊断 网络性能监控 网络流量分析工具&#xff1a;使用Wireshark、NetFlow、Ntop等工具监…...

[C++String]接口解读,深拷贝和浅拷贝,string的模拟实现

&#x1f496;&#x1f496;&#x1f496;欢迎来到我的博客&#xff0c;我是anmory&#x1f496;&#x1f496;&#x1f496; 又和大家见面了 欢迎来到C探索系列 作为一个程序员你不能不掌握的知识 先来自我推荐一波 个人网站欢迎访问以及捐款 推荐阅读 如何低成本搭建个人网站…...

理性看待、正确理解 AI 中的 Scaling “laws”

编者按&#xff1a;LLMs 规模和性能的不断提升&#xff0c;让人们不禁产生疑问&#xff1a;这种趋势是否能一直持续下去&#xff1f;我们是否能通过不断扩大模型规模最终实现通用人工智能&#xff08;AGI&#xff09;&#xff1f;回答这些问题对于理解 AI 的未来发展轨迹至关重…...

【OCR 学习笔记】二值化——全局阈值方法

二值化——全局阈值方法 固定阈值方法Otsu算法在OpenCV中的实现固定阈值Otsu算法 图像二值化&#xff08;Image Binarization&#xff09;是指将像素点的灰度值设为0或255&#xff0c;使图像呈现明显的黑白效果。二值化一方面减少了数据维度&#xff0c;另一方面通过排除原图中…...

Java - IDEA开发

使用IDEA开发Java程序步骤&#xff1a; 创建工程 Project&#xff1b;创建模块 Module&#xff1b;创建包 Package&#xff1b;创建类&#xff1b;编写代码&#xff1b; 如何查看JDK版本 Package介绍: package是将项目中的各种文件,比如源代码、编译生成的字节码、配置文件、…...

Oracle(62)什么是内存优化表(In-Memory Table)?

内存优化表&#xff08;In-Memory Table&#xff09;是指将表的数据存储在内存中&#xff0c;以提高数据访问和查询性能的一种技术。内存优化表通过利用内存的高速访问特性&#xff0c;显著减少I/O操作的延迟&#xff0c;提升数据处理的速度。这种技术在需要高性能数据处理的应…...