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

linux0.11内核源码修仙传第十六章——获取硬盘信息

🚀 前言

    书接第十四章:linux0.11内核源码修仙传第十四章——进程调度之fork函数,在这一节博客中已经通过fork进程创建了一个新的进程1,并且可以被调度,接下来接着主线继续走下去。希望各位给个三连,拜托啦,这对我真的很重要!!!

目录

  • 🚀 前言
  • 🏆硬盘基本信息的赋值
  • 🏆硬盘分区表的设置
    • 📃硬盘分区表(Disk Partition Table,DPT)
    • 📃代码实现
  • 🏆加载根文件系统
    • 📃mount_root 整体解读
    • 📃内存中用于文件系统的数据结构
      • 文件信息初始化
      • 超级块初始化
      • inode信息读取
      • 记录位图信息
      • 记录inode位图信息
  • 🎯总结
  • 📖参考资料

🏆硬盘基本信息的赋值

    好久没回顾 main 函数了,来回顾一下:

void main(void)
{···mem_init(main_memory_start,memory_end);trap_init();blk_dev_init();chr_dev_init();tty_init();time_init();sched_init();buffer_init(buffer_memory_end);hd_init();floppy_init();sti();move_to_user_mode();if (!fork()) {		/* we count on this going ok */init();}for(;;) pause();
}

    这里面前面的一堆初始化已经看完了,fork函数也运行了,成功创建了进程1。进程1会返回0,。现在压力来到了init函数:

void init(void)
{int pid,i;setup((void *) &drive_info);(void) open("/dev/tty0",O_RDWR,0);(void) dup(0);(void) dup(0);printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,NR_BUFFERS*BLOCK_SIZE);printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);if (!(pid=fork())) {close(0);if (open("/etc/rc",O_RDONLY,0))_exit(1);execve("/bin/sh",argv_rc,envp_rc);_exit(2);}if (pid>0)while (pid != wait(&i))/* nothing */;while (1) {if ((pid=fork())<0) {printf("Fork failed in init\r\n");continue;}if (!pid) {close(0);close(1);close(2);setsid();(void) open("/dev/tty0",O_RDWR,0);(void) dup(0);(void) dup(0);_exit(execve("/bin/sh",argv,envp));}while (1)if (pid == wait(&i))break;printf("\n\rchild %d died with code %04x\n\r",pid,i);sync();}_exit(0);	/* NOTE! _exit, not exit() */
}

    ok,fine,里面内容很多,没关系,一点点来,这一篇博文来看第一行 setup 函数的内容。

struct drive_info { char dummy[32]; } drive_info;void init(void)
{setup((void *) &drive_info);···
}

    先来看看传入的参数:drive_info 。这个变量是来自内存 0x90080 的数据,设置是在main函数的最开始。详情可以看博客:linux0.11内核源码修仙传第二章——setup.s,内存里的存放位置如下所示:

在这里插入图片描述

    接下来来看setup函数:

static inline _syscall1(int,setup,void *,BIOS)

    好的,这又是一个系统调用,返回类型是int,有一个参数是 void * 类型的BIOS。有关于系统调用可以参考这篇博客:linux0.11内核源码修仙传第十四章——进程调度之fork函数。其实直白一点,可以直接去系统调用的sys_call_table里面找对应的函数,这里讲结论,它会直接调用 sys_setup 函数:

int sys_setup(void * BIOS)
{···hd_info[0].cyl = *(unsigned short *) BIOS;			// 总柱面数hd_info[0].head = *(unsigned char *) (2+BIOS);		// 磁头数hd_info[0].wpcom = *(unsigned short *) (5+BIOS);	// 写入补偿hd_info[0].ctl = *(unsigned char *) (8+BIOS);		// 控制字节hd_info[0].lzone = *(unsigned short *) (12+BIOS);	// 逻辑区域起始柱面hd_info[0].sect = *(unsigned char *) (14+BIOS);		// 每磁道扇区数BIOS += 16;	···
}

    上面是这个函数的第一部分,对硬盘基本信息的赋值。BIOS是来自内存 0x90080 处的数据,包括柱面数、磁头数、扇区数等信息。不了解这些信息的可以看参考资料[3]。其实这里本来是个循环的,循环赋值所有硬盘信息进hd_info这个结构体数组,但是这里只考虑一个盘的情况,因此去掉了循环。最后BIOS加了16可以看上面内存的图,硬盘1和硬盘2参数之间隔了16字节。这里是准备到下一个硬盘了,但是这里没有了,所以不作考虑。

    最终结果如下所示:

在这里插入图片描述

🏆硬盘分区表的设置

📃硬盘分区表(Disk Partition Table,DPT)

    硬盘分区表用于定义硬盘的分区信息。分区表存储在硬盘的某个特定区域,通常是硬盘的第一个扇区,称为主引导记录(Master Boot Record, MBR),现代的分区表格式则主要是GPT(GUID Partition Table)。其作用主要是告诉操作系统硬盘上有多少个分区,每个分区的大小和位置

📃代码实现

    在linux0.11中的做法如下所示:

int sys_setup(void * BIOS)
{···hd[0].start_sect = 0;hd[0].nr_sects = hd_info[i].head*hd_info[i].sect*hd_info[i].cyl;struct buffer_head *bh = bread(0x300 + drive*5,0);struct partition *p = 0x1BE + (void *)bh->b_data;for (int i=1;i<5;i++,p++) {hd[i].start_sect = p->start_sect;hd[i].nr_sects = p->nr_sects;}brelse(bh);···
}

    其实仔细看就能看出来,只是给一个新的结构体数组 hd 做赋值,而且这个结构体里面就两个成员:start_sectnr_sects ,也就是开始扇区和总扇区数来记录。循环里面一共4次,加上最开始初始化的,因此一共是五个分区,最后结果如下所示:

在这里插入图片描述

    这些信息从哪里获取呢,就是在硬盘的第一个扇区的 0x1BE 偏移处,这里存储着该硬盘的分区信息,只要把这个地方的数据拿到就 OK 了。

    所以 bread 就是干这事的,从硬盘读取数据:

struct buffer_head *bh = bread(0x300 + drive*5,0);

    第一个参数 0x300 是第一块硬盘的主设备号,就表示要读取的块设备是硬盘一。第二个参数 0 表示读取第一个块,一个块为 1024 字节大小,也就是连续读取硬盘开始处 0 ~ 1024 字节的数据。拿到这部分数据后,再取 0x1BE 偏移处,就得到了分区信息:

struct partition *p = 0x1BE + (void *)bh->b_data;

    从硬盘的视角来看分区。0号块本来是一个超级块,可以参考这篇博客:linux0.11内核源码修仙传第十五章——文件系统,现在在里面多放一个分区信息。下面是示意图:

在这里插入图片描述

    至于如何从硬盘中读取指定位置(块)的数据,也就是 bread 函数的内部实现,这部分略微复杂,先埋个坑日后再细聊。

🏆加载根文件系统

    最后setup函数还有一部分:

int sys_setup(void * BIOS)
{···rd_load();		// 不用管mount_root();···
}

    其中 rd_load 是当有 ramdisk 时,也就是虚拟内存盘,才会执行。虚拟内存盘是通过软件将一部分内存(RAM)模拟为硬盘来使用的一种技术,此处当不存在,因此这行代码无用。

    mount_root是加载根文件系统,有了它之后,操作系统才能从一个根开始找到所有存储在硬盘中的文件,所以它是文件系统的基石,很重要:

void mount_root(void)
{int i,free;struct super_block * p;struct m_inode * mi;if (32 != sizeof (struct d_inode))panic("bad i-node size");for(i=0;i<NR_FILE;i++)file_table[i].f_count=0;if (MAJOR(ROOT_DEV) == 2) {printk("Insert root floppy and press ENTER");wait_for_keypress();}for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {p->s_dev = 0;p->s_lock = 0;p->s_wait = NULL;}if (!(p=read_super(ROOT_DEV)))panic("Unable to mount root");if (!(mi=iget(ROOT_DEV,ROOT_INO)))panic("Unable to read root i-node");mi->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */p->s_isup = p->s_imount = mi;current->pwd = mi;current->root = mi;free=0;i=p->s_nzones;while (-- i >= 0)if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))free++;printk("%d/%d free blocks\n\r",free,p->s_nzones);free=0;i=p->s_ninodes+1;while (-- i >= 0)if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))free++;printk("%d/%d free inodes\n\r",free,p->s_ninodes);
}

📃mount_root 整体解读

    从整体上来说,mount_root 这个函数就是要把硬盘中的数据以文件系统的格式进行解读,加载到内存中设计好的数据结构,这样操作系统就可以通过内存中的数据,以文件系统的方式访问硬盘中的一个个文件。首先回顾一下硬盘中的文件系统格式,区别于之前我们的博客里介绍的文件系统,哪个是ext2的格式,但是linux-0.11是MINIX文件系统,但是都是大同小异的,这里贴出来这个文件系统的格式:

在这里插入图片描述

    简单看看这个文件系统:

引导块:启动区,当然不一定所有的硬盘都有启动区,但我们还是得预留出这个位置,以保持格式的统一。
超级块:用于描述整个文件系统的整体信息,我们看它的字段就知道了,有后面的 inode 数量,块数量,第一个块在哪里等信息。
inode位图:inode的使用情况。
块位图:块的使用情况。
i 结点:inode存放每个文件或目录的元信息和索引信息。
块:存放文件数据。

    可是硬盘中凭什么就有了这些信息呢?这就是个鸡生蛋蛋生鸡的问题了。你可以先写一个操作系统,然后给一个硬盘做某种文件系统类型的格式化,这样你就得到一个有文件系统的硬盘了,有了这个硬盘,你的操作系统就可以成功启动了。

📃内存中用于文件系统的数据结构

文件信息初始化

    下面来逐步看,就只看第一个循环目前:

void mount_root(void)
{for(i=0;i<64;i++)file_table[i].f_count=0;···
}

    这个循环就干了一件事,把 64 个 file_table 里的 f_count 清零。来看看具体这个 file_table,其表示进程所使用的文件,进程每使用一个文件都需要记录在这里面,包括文件类型,inode索引信息,引用次数f_count,现在没有被引用,所以先将其都置为0。来看看代码里的具体实现:

struct file file_table[NR_FILE];struct file {unsigned short f_mode;unsigned short f_flags;unsigned short f_count;struct m_inode * f_inode;off_t f_pos;
};

    来看一个file_table的使用案例。比如现在有如下的命令:echo "hello" > 0 。这个命令表示将字符串“hello”写入到0号文件描述符。这个0号文件就是file_table[0]对应的文件。这个文件在硬盘哪里呢?注意到其中有个f_inode成员,通过这个即可找到indoe信息,inode里面包含了一个文件所需要的全部信息,包括文件大小,文件类型,文件所在硬盘号等。此事已在前面有所记载。

超级块初始化

    接着看这个函数后面的内容:

void mount_root(void)
{···for(p = &super_block[0] ; p < &super_block[8] ; p++) {p->s_dev = 0;p->s_lock = 0;p->s_wait = NULL;}···
}

    这又是一个初始化的操作。super_block 就是我们之前讲的超级块,其作用也和之前的超级块一样,里面存的这个把设备的信息,通过这个超级块就可以掌握整个设备的文件系统全局了。

s_dev :超级块对应的设备号,置为 0 表示未使用。
s_lock :超级块锁,置为 0(未锁定)
s_wait :等待队列指针,置为 NULL

    来看接下来的操作:

void mount_root(void)
{···if (!(p=read_super(0)))panic("Unable to mount root");···
}

    接下来就是读取硬盘的超级块信息到内存中,read_super 函数就是读取硬盘中的超级块。

inode信息读取

    接下来读取根目录的inode信息。

int ROOT_DEV = 0;
#define ROOT_INO 1void mount_root(void)
{···if (!(mi=iget(ROOT_DEV, ROOT_INO)))panic("Unable to read root i-node");mi->i_count += 3 ;	// 逻辑上使用4次,初始为1···
}

    iget函数会获取根inode,同时会增加inode引用次数,表示inode被使用。

    接下来就是将 inode 设置当前进程(新建的进程1)的根目录和工作目录:

void mount_root(void)
{···p->s_isup = p->s_imount = mi;current->pwd = mi;		// 当前工作目录(m_inode指针)current->root = mi;		// 根目录(m_inode指针)···
}

记录位图信息

    超级块下面是块位图:

void mount_root(void)
{···free=0;i=p->s_nzones;		// 文件系统的总磁盘块数while (-- i >= 0)if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))free++;···
}

    首先来看看结构体p的内容:s_zmap 是位图数组,每个元素指向一个页,b_data是页的内存地址。用于管理块的占用状态。i>>13 是因为一页是 2^13 个块,超出了就是其他页,就是其他索引了。

    其次来搞清楚set_bit函数的含义:

#define set_bit(bitnr,addr) ({ \
register int __res __asm__("ax"); \
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })

    这个不是设置位!!!是检查位的值。addr 的第 bitnr 位为 1,返回 1;否则返回 0。

    8191换算成二进制是这个:1 1111 1111 1111,共13个1,这是取出低13位的值。为什么是13呢?那是因为在早期文件系统,如 MINIX。每个位图页管理8192(2^13)个块。i&8191 表示位图页内偏移。合起来就是检查每个块对应的位是否为0,0就是空闲,就递增free变量。通过 i >> 13i & 8191 分页定位位图中的位。

    free变量的含义就是统计文件系统中未被占用的磁盘块(空闲块)数量。

记录inode位图信息

    最后就是inode位图:

void mount_root(void)
{···free=0;i=p->s_ninodes+1;while (-- i >= 0)if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))free++;···
}

    做法和目标同上面的块位图,只是i的值不一样。

🎯总结

    这篇博客就主要讲了setup函数的内容,获硬盘信息以及加载根文件。


📖参考资料

[1] linux源码趣读
[2] 一个64位操作系统的设计与实现
[3] 硬盘基本知识(磁道、扇区、柱面、磁头数、簇、MBR、DBR)
[4] 分区表(Partition Table)是计算机硬盘驱动器上一个重要的数据结构

相关文章:

linux0.11内核源码修仙传第十六章——获取硬盘信息

&#x1f680; 前言 书接第十四章&#xff1a;linux0.11内核源码修仙传第十四章——进程调度之fork函数&#xff0c;在这一节博客中已经通过fork进程创建了一个新的进程1&#xff0c;并且可以被调度&#xff0c;接下来接着主线继续走下去。希望各位给个三连&#xff0c;拜托啦&…...

画家沈燕的山水实验:在传统皴法里植入时代密码

导语&#xff1a;当宋代山水遇上AI算法&#xff0c;当青绿颜料邂逅生态数据&#xff0c;沈燕在宣纸与人工智能的交界处&#xff0c;开启了一场关于水墨基因的“基因突变”实验。她的画笔既似考古学家的洛阳铲&#xff0c;又似未来学家的扫描仪&#xff0c;在古今对话中重构山水…...

聊聊四种实时通信技术:短轮询、长轮询、WebSocket 和 SSE

这篇文章&#xff0c;我们聊聊 四种实时通信技术&#xff1a;短轮询、长轮询、WebSocket 和 SSE 。 1 短轮询 浏览器 定时&#xff08;如每秒&#xff09;向服务器发送 HTTP 请求&#xff0c;服务器立即返回当前数据&#xff08;无论是否有更新&#xff09;。 优点&#xff1…...

国联股份卫多多与北京经纬智诚签署战略合作协议

5月9日&#xff0c;北京经纬智诚电子商务有限公司&#xff08;以下简称“经纬智诚”&#xff09;总经理王学文一行到访国联股份卫多多&#xff0c;同卫多多/纸多多副总裁、产发部总经理段任飞&#xff0c;卫多多机器人产业链总经理郭碧波展开深入交流&#xff0c;双方就未来合作…...

在 Envoy 的配置文件中出现的 “@type“ 字段

在 Envoy 的配置文件中出现的 "type" 字段是 Protocol Buffers&#xff08;Protobuf&#xff09;的 JSON/YAML 编码规范的一部分&#xff0c;属于 Typed Struct 的表示方式。它的作用是明确指定当前配置对象的 Protobuf 类型&#xff0c;以便 Envoy 正确解析配置。以…...

编译原理实验 之 语法分析程序自动生成工具Yacc实验

文章目录 实验环境准备复现实验例子分析总的文件架构实验任务 什么是Yacc Yacc(Yet Another Compiler Compiler)是一个语法分析程序自动生成工具&#xff0c;Yacc实验通常是在编译原理相关课程中进行的实践项目&#xff0c;旨在让学生深入理解编译器的语法分析阶段以及掌握Yac…...

【大模型】LLM概念相关问题(上)

1.主流的大语言模型 截至2025年&#xff0c;主流的大型语言模型&#xff08;LLM&#xff09;体系涵盖了多个国家和机构的成果&#xff0c;具有多样的架构设计、参数规模和应用场景。以下是一些具有代表性的开源和闭源 LLM 体系&#xff1a; &#x1f1fa;&#x1f1f8; OpenA…...

AWS IoT Core与MSK集成实战:打造高可靠实时IoT数据管道

在物联网快速发展的今天,如何高效、安全地处理海量设备数据成为企业面临的一大挑战。本文将带您深入探索AWS IoT Core与Amazon MSK(Managed Streaming for Apache Kafka)的集成方案,手把手教您搭建一个可靠、可扩展的实时IoT数据处理管道。无论您是IoT开发者、大数据工程师还是…...

智慧交通-车门开关状态检测数据集VOC+YOLO格式1006张2类

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1006 标注数量(xml文件个数)&#xff1a;1006 标注数量(txt文件个数)&#xff1a;1006 …...

【传感器】代码——DHT11温湿度传感器

目录 一、代码流程 二、模块.c代码 三、模块.h代码 四、主函数代码 一、代码流程 1.模块复位&#xff1a;主机发送开始通信时序&#xff0c;从机做出响应&#xff08;需检测是否有响应&#xff09; 2.MCU读取1Bit数据 3.MCU读取1Byte数据 4.MCU读取8Byte数据组成完整Dat…...

MySQL 的事务(Transaction)

1. 什么是事务&#xff1f;​​ 事务是​​一组原子性的数据库操作序列​​&#xff0c;这些操作要么​​全部执行成功​​&#xff0c;要么​​全部失败回滚​​。事务的目的是确保数据库从一个一致状态转换到另一个一致状态&#xff0c;即使在执行过程中发生错误或中断。 ​…...

vue知识点总结 依赖注入 动态组件 异步加载

一 依赖注入 使用场景&#xff1a;当需要多层组件需要传值 如 祖宗-》父亲-》儿子-》孙子如祖宗的数据需要直接传给孙子 在祖宗组件中写&#xff1a; data(){return {}} provide(){ return {shujukey:数据值 } }在孙子组件中接收,模板代码中直接使用{{shujukey}}获取数据 dat…...

【软件设计师:存储】16.计算机存储系统

一、主存储器 存储器是计算机系统中的记忆设备,用来存放程序和数据。 计算机中全部信息,包括输入的原始数据、计算机程序、中间运 行结果和最终运行结果都保存在存储器中。 存储器分为: 寄存器Cache(高速缓冲存储器)主存储器辅存储器一、存储器的存取方式 二、存储器的性…...

快速开发-基于gin的中间件web项目开发

一、概述 在 Gin 框架中&#xff0c;中间件&#xff08;Middleware&#xff09;是一种在处理 HTTP 请求之前或之后执行的函数。使用中间件可以方便地实现诸如身份验证&#xff08;Auth&#xff09;、日志记录、请求限流等功能。 二、编写中间件 // 中间件 func StartCost1(c …...

耀圣-气动带刮刀硬密封法兰球阀:攻克颗粒高粘度介质的自清洁 “利器”

气动带刮刀硬密封法兰球阀&#xff1a;攻克颗粒高粘度介质的自清洁 “利器” 在化工、矿业、食品加工等行业中&#xff0c;带颗粒高粘度介质、料浆及高腐蚀性介质的输送与控制一直是行业难题。普通阀门极易因介质附着、颗粒堆积导致卡阻失效&#xff0c;密封面磨损加剧&#x…...

MySQL + Elasticsearch:为什么要使用ES,使用场景与架构设计详解

MySQL Elasticsearch&#xff1a;为什么要使用ES&#xff0c;使用场景与架构设计详解 前言一、MySQL Elasticsearch的背景与需求1.1 为什么要使用Elasticsearch&#xff08;ES&#xff09;&#xff1f;1.2 为什么MySQL在某些场景下不足以满足需求&#xff1f;1.3 MySQL Elas…...

【C语言】--指针超详解(三)

目录 一.数组名的理解 二.使用指针访问数组 三.一维数组传参的本质 四.冒泡排序 五.二级指针 六.指针数组 6.1--指针数组的定义 6.2--指针数组模拟二维数组 &#x1f525;个人主页&#xff1a;草莓熊Lotso的个人主页 &#x1f3ac;作者简介&#xff1a;C方向学习者 &…...

污水处理厂逆袭:Ethernet/IP 转 CANopen 开启“智净”时代

在我们的日常生活中&#xff0c;污水处理厂发挥着至关重要的作用&#xff0c;它们处理着城市污水&#xff0c;确保我们的水源安全。然而&#xff0c;这些关键设施的运行和管理并非易事&#xff0c;尤其是在数字化转型的大潮中。现在&#xff0c;我们有了一款创新的解决方案——…...

ROS导航局部路径规划算法

在导航功能包中&#xff0c;局部路径规划器的位置如图红框所示。它接受全局路径规划器生成的全局路径以及里程计信息和局部代价地图&#xff0c;最后输出速度控制信息 一、DWA&#xff08;Dynamic Window Approach&#xff09; 原理介绍 DWA 是一种基于动态窗口采样的局部路…...

《深挖Java中的对象生命周期与垃圾回收机制》

大家好呀&#xff01;&#x1f44b; 今天我们要聊一个Java中超级重要的话题——对象的生命周期和垃圾回收机制。 一、先来认识Java世界的"居民"——对象 &#x1f476; 在Java世界里&#xff0c;一切皆对象。就像现实世界中的人一样&#xff0c;每个Java对象也有自…...

Java——包装类

目录 3.5 包装类 3.5 包装类 有时需要把基本类型转换为对象。所有基本类型都有一个与之对应的类。这些类称为包装器/类。这些类是不可变类&#xff0c;即一旦构造了包装器/类&#xff0c;就不允许改变包装在其中的值。其次包装类还是final&#xff0c;不用可以被继承。 为什么要…...

【谭浩强】第七章第14题

实验结果&#xff1a;当M1时输出的结果 实验总结&#xff1a;用define定义要频繁使用的值可以节省时间&#xff1b;求完一门课平均成绩之后要让sum重新等于0&#xff1b;求最高分对应的学生和对应的课程要循环完一遍覆盖一遍r和c的值&#xff1b; 程序代码 #include <stdi…...

Linux 内核中的 security_sk_free:安全模块与 Socket 释放机制解析

引言 在 Linux 内核中,网络通信和进程间交互(IPC)的核心数据结构之一是 struct sock(即 socket)。其生命周期管理涉及复杂的资源分配与释放逻辑。本文聚焦于 security_sk_free 这一函数,探讨其作用、调用场景以及与安全模块的交互机制,并解答一个常见疑问:在单机间 TC…...

学习笔记:黑马程序员JavaWeb开发教程(2025.4.1)

11.10 案例-配置文件-yml配置文件 Yml语法&#xff1a; 数据格式&#xff1a; 11.11 案例-配置文件-ConfigurationProperties 配置项自动注入&#xff0c;需要保持KEY的属性名一样&#xff0c;需要在文件中加上Data注解&#xff0c;要将这个类交给IOC容器管理&#xff0c;使其成…...

深度学习-161-Dify工具之对比使用工作流和聊天流生成图表可视化的html文件

文章目录 1 任务背景2 使用chatflow聊天流2.1 开始节点2.2 文档提取器2.3 LLM2.4 参数提取器2.5 代码执行2.6 直接回复2.7 应用展示3 生成html文件可视化图表3.1 使用workflow工作流3.1.1 LLM3.1.2 效果展示3.2 使用chatflow聊天流3.2.1 LLM3.2.2 效果展示4 参考附录分别使用聊…...

关于VScode的调试

调试代码要有这么几个工具&#xff1a;源代码、带调试符号的程序、MAP表&#xff0c;调试器。 在启动调试器之前&#xff0c;要首先编译带有符号表的程序&#xff0c;生成对应map。然后启动调试器。 不同的语言有不同的特性&#xff0c;比如解释型语言不需要编译成可执行程序…...

(x ^ 2 + 2y − 1) ^ 3 − x ^ 2 * y ^ 3 = 1

二元高次方程 EquationSolver20250509.java package math;import org.apache.commons.math3.analysis.MultivariateFunction; import org.apache.commons.math3.optim.InitialGuess; import org.apache.commons.math3.optim.MaxEval; import org.apache.commons.math3.optim.P…...

弹窗表单的使用,基于element-ui二次封装

el-dialog-form 介绍 基于element-ui封装的弹窗式表单组件 示例 git地址 https://gitee.com/chenfency/el-dialog-form.git 更新日志 2021-8-12 版本1.0.0 2021-8-17 优化组件&#xff0c;兼容element原组件所有Attributes及Events 2021-9-9 新增tip提示 安装教程 npm install …...

关系模式-无损连接和保持函数依赖的判断

1、怎样判断一个关系模式的分解是否是无损连接&#xff1f; 方法一&#xff1a;公式定理法 关系模式R<U,F>的一个分解具有无损连接的充分必要条件是&#xff1a; 或 方法二&#xff1a;表格法&#xff08;常用与分解成3个及以上关系模式&#xff09; a. 通过立一张j…...

Vmware 最新下载教程和安装教程,外带免下载文件

一、VMware 的简介 VMware 是一款功能强大的桌面虚拟计算机软件&#xff0c;提供用户可在单一的桌面上同时运行不同的操作系统&#xff0c;和进行开发、测试 、部署新的应用程序的最佳解决方案。VMware可在一部实体机器上模拟完整的网络环境&#xff0c;以及可便于携带的虚拟机…...

开平机:从原理到实践的全面技术剖析

一、开平机核心模块技术解析 1. 校平辊系的力学建模与辊型设计 校平机精度核心在于辊系设计&#xff0c;需通过弹塑性力学模型计算变形量。典型校平辊配置参数&#xff1a; 辊径比&#xff1a;校平辊直径&#xff08;D&#xff09;与板材厚度&#xff08;t&#xff09;需满足…...

Edu教育邮箱申请2025年5月

各位好&#xff0c;这里是aigc创意人竹相左边 如你所见&#xff0c;这里是第3部分 现在是选择大学的学科专业 选专业的时候记得考虑一下当前的时间日期。 比如现在是夏天&#xff0c;所以你选秋天入学是合理的。...

文本框碰撞测试

1.核心代码: // 初始化舞台和变量 var stage, textField, bounds, velocity;function init() {// 创建舞台stage = new createjs.Stage("canvas");// 设置矩形边界bounds = {x: 50, y: 50, width: 400, height: 300};// 绘制边界矩形var border = new createjs.Shap…...

LeRobot 项目部署运行逻辑(六)——visualize_dataset_html.py/visualize_dataset.py

可视化脚本包括了两个方法&#xff1a;远程下载 huggingface 上的数据集和使用本地数据集 脚本主要使用两个&#xff1a; 目前来说&#xff0c;ACT 采集训练用的是统一时间长度的数据集&#xff0c;此外&#xff0c;这两个脚本最大的问题在于不能裁剪&#xff0c;这也是比较好…...

Python函数:从基础到进阶的完整指南

在Python编程中&#xff0c;函数是构建高效、可维护代码的核心工具。无论是开发Web应用、数据分析还是人工智能模型&#xff0c;函数都能将复杂逻辑模块化&#xff0c;提升代码复用率与团队协作效率。本文将从函数基础语法出发&#xff0c;深入探讨参数传递机制、高阶特性及最佳…...

图灵爬虫练习平台第七题千山鸟飞绝js逆向

题目七&#xff1a;千山鸟飞绝 还是先进入开发者模式&#xff0c;一进来还是一个无限debugger&#xff0c;直接右键点击一律不在此处停留 然后点击下一页&#xff0c;复制curl进行代码生成&#xff0c;然后就会发现加密内容是headers中的m,ts&#xff0c;还有参数中的x&#xf…...

使用Python和OpenCV实现实时人脸检测与识别

前言 在计算机视觉领域&#xff0c;人脸检测与识别是两个非常重要的任务。人脸检测是指在图像中定位人脸的位置&#xff0c;而人脸识别则是进一步识别出人脸的身份。随着深度学习的发展&#xff0c;这些任务的准确性和效率都有了显著提升。OpenCV是一个开源的计算机视觉库&…...

Excel实现单元格内容拼接

一、应用场景&#xff1a; 场景A&#xff1a;将多个单元格拼接&#xff0c;比如写测试用例时&#xff0c;将多个模块拼接&#xff0c;中间用“-”隔开 场景B&#xff1a;将某单元格内容插入另一单元格固定位置&#xff08;例如在B1中添加A1的内容&#xff09; 二、实际应用&a…...

C语言实现:打印素数、最大公约数

本片博客起源于作者在经历了学校的测试之后猛然发现自己居然忘记了一些比较基础的代码&#xff0c;因此写了本片博客加强记忆 以下算法仅供参考 打印素数 打印&#xff1a;0到200之间所有的素数 #define _CRT_SECURE_NO_WARNINGS#include<stdio.h> #include<math.h&…...

TDengine 在智慧油田领域的应用

简介 智慧油田&#xff0c;亦称为数字油田或智能油田&#xff0c;是一种采用尖端信息技术与先进装备的现代油田开发模式。该模式通过实时更新油气田层析图及动态生产数据&#xff0c;显著提高了油气田的开发效率与经济价值。 信息技术在此领域发挥着至关重要的作用&#xff0…...

将 iconfont 图标转换成element-plus也能使用的图标组件

在做项目时发现&#xff0c;element-plus的图标组件&#xff0c;不能像文档示例中那样使用 iconfont 的图标。经过研究发现&#xff0c;element-plus的图标封装成了vue组件&#xff0c;组件内容是一个svg&#xff0c;然后以组件的方式引入和调用图标。根据这个思路&#xff0c;…...

使用程序绘制中文字体——中文字体的参数化设计方案初探

目录 写在前面基本设计思路笔画骨架参数设计笔画风格参数设计起笔风格转角风格字重变化弯曲程度 字形的“组装拟合”基于骨架的结构调整笔画绘制二三事撇的两侧轮廓绘制——不是两条贝塞尔曲线那么简单转角的处理&#xff0c;怎样能显得不突兀&#xff1f;笔画骨架关键点的拖拽…...

高频数据结构面试题总结

基础数据结构 1. 数组(Array) 特点&#xff1a;连续内存、固定大小、随机访问O(1)常见问题&#xff1a; 两数之和/三数之和合并两个有序数组删除排序数组中的重复项旋转数组最大子数组和(Kadane算法) 2. 链表(Linked List) 类型&#xff1a;单链表、双链表、循环链表常见问…...

工业设计破局密码:3D 可视化技术点燃产业升级引擎

3D可视化是一种将数据、信息或抽象概念以三维图形、模型和动画的形式呈现出来的技术。3D可视化技术通过构建三维数字孪生体&#xff0c;将设计思维转化为可交互的虚拟原型&#xff0c;不仅打破了传统二维设计的空间局限&#xff0c;更在效率、精度与用户体验层面开创了全新维度…...

【动态导通电阻】p-GaN HEMTs正向和反向导通下的动态导通电阻

2024 年,浙江大学的 Zonglun Xie 等人基于多组双脉冲测试方法,研究了两种不同技术的商用 p-GaN 栅极 HEMTs 在正向和反向导通模式以及硬开关和软开关条件下的动态导通电阻(RON)特性。实验结果表明,对于肖特基型 p-GaN 栅极 HEMTs,反向导通时动态 RON 比正向导通高 3%-5%;…...

Python代码编程基础

字符串 str.[]实现根据下标定位实现对元素的截取 for 循环可以实现遍历 while 循环可以在实现遍历的同时实现对某一下标数值的修改 字符串前加 r 可以实现对字符串的完整内容输出 字符串前加 f 可以实现对字符串内{}中包裹内容的格式化输出&#xff0c;仅在 v3.6 之后可用…...

基于RAG+MCP开发【企文小智】企业智能体

一、业务场景描述 1.1、背景介绍 几乎每家企业都积累了大量关于规章制度的文档资料&#xff0c;例如薪酬福利、绩效考核、保密协议、考勤管理、采购制度、资产管理制度等。这些文档大多以 Word、PDF 等非结构化格式存在。传统方式下&#xff0c;员工在查询某项具体规则时&…...

【软件测试】测试用例的设计方法

目录 一、基于需求进行测试用例的设计 1.1 功能需求测试分析 二、黑盒测试用例设计方法 2.1 等价类划分法(解决穷举) 2.1.1 等价类设计步骤 2.1.2 等价类划分法案例 2.1.2.1 验证 QQ 账号的合法性 2.1.2.2 验证某城市电话号码的正确性 2.1.3 适用场景 2.2 边界值分析…...

计算机网络笔记(十八)——3.5高速以太网

3.5.1 100BASE-T以太网 1. 基本概念 标准规范&#xff1a;IEEE 802.3u&#xff0c;是快速以太网的典型代表&#xff0c;运行速率100Mbps。物理介质&#xff1a;使用双绞线&#xff08;UTP或STP&#xff09;&#xff0c;支持最大传输距离100米&#xff08;Cat5/5e及以上&#…...

海外广告账号资源解析:如何选择适合业务的广告账户?

在全球化数字营销的浪潮下&#xff0c;海外广告投放已成为企业拓展市场的核心手段。然而&#xff0c;不同平台的广告账号类型复杂多样&#xff0c;如何选择适合自身业务的资源&#xff1f;本文将深度解析 Facebook、Google、TikTok 三大平台的广告账号类型&#xff0c;助您精准…...