轻松Linux-7.Ext系列文件系统

天朗气清,惠风和煦,今日无事,遂来更新。


1.概述

总所周知,我们存的数据都是在一个叫硬盘的东西里面,这个硬盘又像个黑盒,这章就来简单解析一下Linux中文件系统。

现在我们用的大都是固态硬盘,除了服务器级别的主机在用机械硬盘,已经很少有人用机械硬盘啦,我们今天就要从机械硬盘讲起。因为Linux中的Ext3、Ext4基本是Ext2文件系统的增强版,所以本章以Ext2文件系统为例。

硬盘里有多层的磁盘和多个磁头,早期的磁盘使用的是CHS(磁道(柱面)、磁头、扇面)定位寻址,而系统需要将CHS地址转换为LBA(Local Block Adress)地址来使用,硬盘就可以看作是一个三维数组,CHS转LBA,就可以看作是将三维数组转化为一维数组

系统读取硬盘的基本单位一般是“块(block)”,块是又n个扇区组成的,系统可以给硬盘分区,分区的最小单位是柱面,柱面内包含各个扇区,即包含了各个块。操作系统为了管理这些分区,引入Ext文件系统,Ext文件系统将各个分区以组为单位分为了n个块组(Block Group),每个块组内记录着本区域内的各种数据,其中就包括了每个存储在此区域文件的inode编号,通过inode以及其中各种位图就可以找到存储文件的属性以及数据,其中包括有各种目录与文件

系统启动时,会自动挂载各个已经预先准备好的分区,只有挂载后分区才可用

Linux中的目录也是文件,属性(元数据)与一般文件区别不大,数据存储的是目录名与目录下存储的各种文件的inode的映射关系,可以将目录看作一个一维数组,里面可能存有别的目录也可能是文件。

访问文件时,其实是打开当前工作目录通过文件名找到对应的inode,去查找文件内容,因此系统要解析文件路径,通过在内核中维护的树状路径结构的结构体struct dentry查找文件,如果找到了就会返回文件的属性inode和内容,如果没找到就会将文件的struct dentry添加到内核缓冲中(每个文件都有对应的dentry结构)

Linux中还有软链接和硬链接,软链接有点像Windows中的快捷访问方式,硬链接相当备份,原理是引用计数。


2.硬盘与CHS和LBA

这里用一张简单的硬盘剖面图来展开:

【计算机组成原理】快到碗里来,轻松图解硬盘结构~_磁盘结构-CSDN博客

硬盘内有磁头(Head)、磁道(track)、扇区(sector),硬盘通过先定位磁头,再确认访问某个磁道(柱面),最后定位扇区来进行定位。扇区从磁盘中读出和写入信息的最小单位一般是512字节。

我们知道文件 = 属性 + 内容,对于硬盘而言就是多定位几个扇区的事。

硬盘的各种属性:

磁头数:一般每个磁盘的上下两面都会有一个磁头。(传动臂上的磁头是共进退的)

磁道数:从0开始编号,从外往内计数,最靠进轴心和最靠外用于停放磁头的磁道不用作存储数据。

柱面数:由同一柱面上的磁道构成,数量上与一个磁盘盘面的磁道数相同。

扇区数:每个磁道被切分为多个扇区,每个磁道的扇区相同。

磁盘数:盘数。

磁盘容量 = 磁头数 x 磁道(柱面)数 x 每磁道扇区数 x 每扇区字节数。

 硬盘是:由多个柱面构成

2.1CHS与LBA的转换

所以整张硬盘就像是一个三维数组(蛋卷-不是),在寻找某个扇区时,就要先寻找某个柱面,再确定在哪个磁道(其实是磁头),最后再确定扇区,由此CHS寻址就产生了。

我们在C/C++中学过数组,二维数组的下标通过算法转换其实是可以转换成一维数组的,所以CHS转换成LBA其实同理,Belike:

这样CHS就转换为了LBA线性地址。

那么谁来做这个转换工作呢,当然是由硬盘(硬件电路,伺服系统)自己来做。

CHS转成LBA:

单个柱⾯的扇区总数 = 磁头数 * 每磁道扇区。

LBA = 柱⾯号C * 单个柱⾯的扇区总数 + 磁头号H * 每磁道扇区数 + 扇区号S - 1。

即:LBA = 柱⾯号C * (磁头数 * 每磁道扇区数) + 磁头号H * 每磁道扇区数 + 扇区号S - 1。

扇区号通常是从1开始的,⽽在LBA中,地址是从0开始的。

柱⾯和磁道都是从0开始编号的。

总柱⾯,磁道个数,扇区总数等信息,在磁盘内部会⾃动维护,上层开机的时候,会获取到这些参 数。

LBA转成CHS:"//": 表⽰除取

柱⾯号C = LBA // (磁头数*每磁道扇区数,就是单个柱⾯的扇区总数)。

磁头号H = (LBA % (磁头数*每磁道扇区数)) // 每磁道扇区数。

扇区号S = (LBA % 每磁道扇区数) + 1。

2.2有关硬盘的各个属性

2.2.1“块”

操作系统在读取硬盘(典型的“块”设备)数据的时候,并不会一个一个扇区的读取,而是一次读取多个扇区,就是以“块”为单位进行读取,硬盘的分区被分为各个块,块的大小是在格式化的时候设置的,并非不可改变的,通常来说由8个扇区组成一个块,即一个块 = 4096字节(4KB)

硬盘我们可以看作是一个三维数组,把他转换为一维数组后数组下标就是LBA,每一个扇区都LBA。

已知LBA:块号 = LBA / 8 (整除)。

已知块:LBA = 块号 * 8 + n(块内第几个扇区)。

那么块是怎么划分的呢?我们后面讲。

2.2.2分区

硬盘的分区,其实就是给硬盘进行格式化,柱面是分区的最小单位(为了保证物理连续性,减少碎片化)。

2.2.3“inode”

我们都知道文件 = 属性 + 内容,并且我们目前还知道文件的内容存在块中,为什么还要有inode呢?

其实inode叫做“索引节点”,用于指向文件的属性信息,inode属性信息大小都是一样,通常为128字节或256字节。并且在Linux中inode作为文件的唯一标识。我们来看看inode长什么样↓

指令为 ls -li

第一个属性就是inode,第二个为模式,第三个为硬链接数,第四个为文件所有者,第五个为用户组,第六个为文件大小(字节),第七个为最后修改的日期,最后的为文件名。

下面为源码:

struct ext2_inode {__le16	i_mode;		/* File mode */__le16	i_uid;		/* Low 16 bits of Owner Uid */__le32	i_size;		/* Size in bytes */__le32	i_atime;	/* Access time */__le32	i_ctime;	/* Creation time */__le32	i_mtime;	/* Modification time */__le32	i_dtime;	/* Deletion Time */__le16	i_gid;		/* Low 16 bits of Group Id */__le16	i_links_count;	/* Links count */__le32	i_blocks;	/* Blocks count */__le32	i_flags;	/* File flags */union {struct {__le32  l_i_reserved1;} linux1;struct {__le32  h_i_translator;} hurd1;struct {__le32  m_i_reserved1;} masix1;} osd1;				/* OS dependent 1 */__le32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */__le32	i_generation;	/* File version (for NFS) */__le32	i_file_acl;	/* File ACL */__le32	i_dir_acl;	/* Directory ACL */__le32	i_faddr;	/* Fragment address */union {struct {__u8	l_i_frag;	/* Fragment number */__u8	l_i_fsize;	/* Fragment size */__u16	i_pad1;__le16	l_i_uid_high;	/* these 2 fields    */__le16	l_i_gid_high;	/* were reserved2[0] */__u32	l_i_reserved2;} linux2;struct {__u8	h_i_frag;	/* Fragment number */__u8	h_i_fsize;	/* Fragment size */__le16	h_i_mode_high;__le16	h_i_uid_high;__le16	h_i_gid_high;__le32	h_i_author;} hurd2;struct {__u8	m_i_frag;	/* Fragment number */__u8	m_i_fsize;	/* Fragment size */__u16	m_pad1;__u32	m_i_reserved2[2];} masix2;} osd2;				/* OS dependent 2 */
};
...
#define	EXT2_NDIR_BLOCKS		12
#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)

3.Ext2文件系统

我们上述的文件内容,基本都是由文件系统来管理的,要用硬盘存储数据的话,首先要先把硬盘格式化成某个文件系统的格式,然后才能使用,文件系统存在的目的就是组织和管理硬盘中的数据和文件

在Linux中最常见的文件系统就是Ext2文件系统,Ext3和Ext4基本是Ext2文件系统的增强版,其核心基本没有变化。

Ext文件把整个分区分为n个大小相同的块组,如下图↓

EXT2 File System一起的是Boot Sector(启动块),其大小是确定的1KB,根据PC标准规定,它储存着磁盘分区信息和启动信息,任何文件系统都是无法修改启动块的。

3.1Block Group

我们可以看到Block Group内部分为 Super Block、GDT、Block Bitmap、inode Bitmap、inode Table、Data Blocks。

3.1.1Super Block

Super Block内存储着文件系统本身的结构和信息,描述了整个分区的文件系统信息。记录的信息主要有:bolck和inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写 ⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。如果Super Block被破坏了,整个文件系统就被破坏了。

Super Block在每个组块内都有备份(也有可能是第一个块组有,其他块组可以没有)。系统对Super Block有多个备份,就是为了磁盘部分出现物理问题时文件系统也能正常工作,保证文件系统的Super Block信息可以正常访问。而且每个Super Block存储的数据都相同。

struct ext2_super_block {__le32	s_inodes_count;		/* Inodes count */ √__le32	s_blocks_count;		/* Blocks count */__le32	s_r_blocks_count;	/* Reserved blocks count */ √__le32	s_free_blocks_count;	/* Free blocks count */ √__le32	s_free_inodes_count;	/* Free inodes count */ √__le32	s_first_data_block;	/* First Data Block */ √__le32	s_log_block_size;	/* Block size */__le32	s_log_frag_size;	/* Fragment size */__le32	s_blocks_per_group;	/* # Blocks per group */    √__le32	s_frags_per_group;	/* # Fragments per group */__le32	s_inodes_per_group;	/* # Inodes per group */    √__le32	s_mtime;		/* Mount time */__le32	s_wtime;		/* Write time */__le16	s_mnt_count;		/* Mount count */__le16	s_max_mnt_count;	/* Maximal mount count */__le16	s_magic;		/* Magic signature */__le16	s_state;		/* File system state */__le16	s_errors;		/* Behaviour when detecting errors */__le16	s_minor_rev_level; 	/* minor revision level */__le32	s_lastcheck;		/* time of last check */__le32	s_checkinterval;	/* max. time between checks */__le32	s_creator_os;		/* OS */__le32	s_rev_level;		/* Revision level */__le16	s_def_resuid;		/* Default uid for reserved blocks */__le16	s_def_resgid;		/* Default gid for reserved blocks *//** These fields are for EXT2_DYNAMIC_REV superblocks only.** Note: the difference between the compatible feature set and* the incompatible feature set is that if there is a bit set* in the incompatible feature set that the kernel doesn't* know about, it should refuse to mount the filesystem.* * e2fsck's requirements are more strict; if it doesn't know* about a feature in either the compatible or incompatible* feature set, it must abort and not try to meddle with* things it doesn't understand...*/__le32	s_first_ino; 		/* First non-reserved inode */__le16   s_inode_size; 		/* size of inode structure */  √__le16	s_block_group_nr; 	/* block group # of this superblock */__le32	s_feature_compat; 	/* compatible feature set */__le32	s_feature_incompat; 	/* incompatible feature set */__le32	s_feature_ro_compat; 	/* readonly-compatible feature set */__u8	s_uuid[16];		/* 128-bit uuid for volume */char	s_volume_name[16]; 	/* volume name */char	s_last_mounted[64]; 	/* directory where last mounted */__le32	s_algorithm_usage_bitmap; /* For compression *//** Performance hints.  Directory preallocation should only* happen if the EXT2_COMPAT_PREALLOC flag is on.*/__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */__u16	s_padding1;/** Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.*/__u8	s_journal_uuid[16];	/* uuid of journal superblock */__u32	s_journal_inum;		/* inode number of journal file */__u32	s_journal_dev;		/* device number of journal file */__u32	s_last_orphan;		/* start of list of inodes to delete */__u32	s_hash_seed[4];		/* HTREE hash seed */__u8	s_def_hash_version;	/* Default hash version to use */__u8	s_reserved_char_pad;__u16	s_reserved_word_pad;__le32	s_default_mount_opts;__le32	s_first_meta_bg; 	/* First metablock block group */__u32	s_reserved[190];	/* Padding to the end of the block */
};

3.1.2GDT

GDT(块组描述符表),描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描 述符存储⼀个块组的描述信息,如在这个块组中从哪⾥开始是inodeTable,从哪⾥开始是Data Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。

struct ext2_group_desc
{__le32	bg_block_bitmap;		/* Blocks bitmap block */__le32	bg_inode_bitmap;		/* Inodes bitmap block */__le32	bg_inode_table;		/* Inodes table block */__le16	bg_free_blocks_count;	/* Free blocks count */__le16	bg_free_inodes_count;	/* Free inodes count */__le16	bg_used_dirs_count;	/* Directories count */__le16	bg_pad;__le32	bg_reserved[3];
};

3.1.3Block Bitmap

块位图,记录着Data Block中每个块的占用信息,可以知道哪个块被占用。

3.1.4Inode Bitmap

inode位图中,每个bit表示inode是否空闲可用。

3.1.5Inode Table

inode表,当前组的所有inode集合,存放着文件属性,最近修改日期,所属者等等。inode标号以分区为单位整体划分,不可越区访问。

3.1.6Data Block

数据区,存放着一个个Block:存放⽂件内容。

根据不同的⽂件类型有以下⼏种情况:

对于普通⽂件,⽂件的数据存储在数据块中。

对于⽬录,该⽬录下的所有⽂件名和⽬录名存储在所在⽬录的数据块中,除了⽂件名外,ls -l命令 看到的其它信息保存在该⽂件的inode中。

3.2inode与Data Block的(简化)映射

inode内部存在
__le32  i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ 
EXT2_N_BLOCKS = 15 ,就是⽤来进⾏inode和block映射的

因此创建⼀个新⽂件主要有以下4个操作:(以图为例)----找的网图

1.存储属性:内核先找到一个空闲的inode节点,内核把文件属性记录到inode中,这里的inode为263466。

2.存储数据:该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。

3.记录分配情况:文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表(GDT)。

4. 添加文件名到目录:新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

3.3目录与路径解析

我们都说,一切皆文件,那么目录是文件吗,怎么理解目录。

实际上目录也是文件,它也是属性 + 内容,不过他的内容存放的是目录下的目录以及文件的映射关系,也就是各个文件名与inode的映射关系

简单抽一段代码看看↓

  1 #include <stdio.h>2 #include <string.h>3 #include <stdlib.h>4 #include <dirent.h>5 #include <sys/types.h>6 #include <unistd.h>7 int main(int argc, char *argv[]) {                                               8     if (argc != 2) {9         fprintf(stderr, "Usage: %s <directory>\n", argv[0]);10         exit(EXIT_FAILURE);11     } 12     DIR *dir = opendir(argv[1]); // ϵͳµ÷Óã¬×ÔÐвéÔÄ13     if (!dir) { 14         perror("opendir");15         exit(EXIT_FAILURE);16     }17     struct dirent *entry;18     while ((entry = readdir(dir)) != NULL) { // ϵͳµ÷Óã¬×ÔÐвéÔÄ19         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..")== 0)20         {21             continue; 22         } 23         printf("Filename: %s, Inode: %lu\n", entry->d_name, (unsigned24             long)entry->d_ino);25     }26     closedir(dir);27     return 0; 28 }

我们可以看到,打开目录就要获得对应的文件名,找到对应的inode号,然后访问目录(文件),本质上是我们必须能打开当前工作目录文件,查看目录文件内容。

这时我们不禁要问,当前我们所在的目录,不是工作目录吗?当前的目录不就打开文件名进来吗,访问不是需要inode吗?我们怎么打开。

Linux中要打开我们当前工作目录,就要有一个层层“递归”的过程,我们要递归到最上层,也就是 "/",我们也叫它根目录,每次访问文件,我们都要从根目录开始,依次打开每一个文件目录,知道找到我们要打开文件的文件名。这个过程就是路径解析。(访问文件: 目录 + 文件名 = 路径)

并且在Linux中访问文件,本质上是由进程进行访问,而进程PCB有CWD(进程的当前工作目录),而我们每次进入目录,打开文件都会被记录,也就有了路径。

根目录是Linux系统提供的目录文件,所以Linux的路径结构是由系统和用户一起构建的

那么问题来了,每次都由根目录打开是否过于慢、低效了。

3.4路径缓存

如果每次都从根目录开始,那确实太低速了。

在Linux系统中,OS会自己缓存历史路径结构,OS会自动维护近期打开的路径结构

Linux在内核中维护的树状路径结构结构体为:struct dentry

struct dentry {/* RCU lookup touched fields */unsigned int d_flags;		/* protected by d_lock */seqcount_t d_seq;		/* per dentry seqlock */struct hlist_bl_node d_hash;	/* lookup hash list */struct dentry *d_parent;	/* parent directory */struct qstr d_name;struct inode *d_inode;		/* Where the name belongs to - NULL is* negative */unsigned char d_iname[DNAME_INLINE_LEN];	/* small names *//* Ref lookup also touches following */struct lockref d_lockref;	/* per-dentry lock and refcount */const struct dentry_operations *d_op;struct super_block *d_sb;	/* The root of the dentry tree */unsigned long d_time;		/* used by d_revalidate */void *d_fsdata;			/* fs-specific data */union {struct list_head d_lru;		/* LRU list */wait_queue_head_t *d_wait;	/* in-lookup ones only */};struct list_head d_child;	/* child of parent list */struct list_head d_subdirs;	/* our children *//** d_alias and d_rcu can share memory*/union {struct hlist_node d_alias;	/* inode alias list */struct hlist_bl_node d_in_lookup_hash;	/* only for in-lookup ones */struct rcu_head d_rcu;} d_u;
} __randomize_layout;

注:

每个⽂件其实都要有对应的dentry结构,包括普通⽂件。这样所有被打开的⽂件,就可以在内存中 形成整个树形结构

整个树形节点也同时会⾪属于LRU(LeastRecentlyUsed,最近最少使⽤)结构中,进⾏节点淘汰

整个树形节点也同时会⾪属于Hash,⽅便快速查找

更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何⽂件,都在先在这 棵树下根据路径进⾏查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry 结构,缓存新路径。

3.5小结

分区之后的格式化操作,就是对分区进⾏分组,在每个分组中写⼊SB、GDT、Block Bitmap、InodeBitmap等管理信息,这些管理信息统称:⽂件系统。

只要知道⽂件的inode号,就能在指定分区中确定是哪⼀个分组,进⽽在哪⼀个分组确定 是哪⼀个inode,进而⽂件属性和内容就全部都有了。

放几个网图帮组理解:


4. 软硬连接

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件,但实际上,新的文件和被引用的文件的inode不同,应用常见上可以想象成一个类似windows的快捷方式

1.硬链接

指令:ln 源文件 链接创建的文件名

我们可以看到硬链接文件的属性几乎是一至的。

. 和 .. 都是硬链接

2.软链接

指令:ln -s 源文件 链接创建的文件名

我们可以看到软链接文件有一个指向性的箭头。


祝大家技术更加精进,文章若有错误请指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96184.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96184.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab机器人工具箱使用4 蒙特卡洛法绘制工作区间

原理&#xff1a;利用rand随机数&#xff0c;给各个关节设置随机关节变量&#xff0c;通过正运动学得到末端位姿变换矩阵&#xff0c;然后利用变换矩阵2三维坐标标记出末端坐标&#xff0c;迭代多次就可以构成点云。教程视频&#xff1a;【MATLAB机器人工具箱10.4 机械臂仿真教…

【项目】在AUTODL上使用langchain实现《红楼梦》知识图谱和RAG混合检索(三)知识图谱和路由部分

首先在数据集 - 开放知识图谱下载红楼梦的知识图谱&#xff0c;这个网站上有各种各样的知识图谱&#xff0c;可以挑你感兴趣的做( • ̀ω•́ ) 这个知识图谱的作者们已经将三元组抽取出来了&#xff0c;我们可以直接用&#xff0c;如果你对三元组是如何生成的感兴趣&#xf…

pycharm 最新版上一次编辑位置

2025nipycharm方法一&#xff1a;用快捷键&#xff08;最方便&#xff09;跳回上一次编辑位置&#xff1a;Windows/Linux: Ctrl Alt ←macOS: ⌘ Option ←跳到前一次位置&#xff1a;Windows/Linux: Ctrl Alt →macOS: ⌘ Option →方法二&#xff1a;显示工具栏按钮在…

前端性能监控与优化:从 Lighthouse 到 APM

在当今竞争激烈的数字环境中&#xff0c;用户对Web应用性能的要求日益提高。一个缓慢或响应迟钝的应用不仅会流失用户&#xff0c;更可能损害品牌形象和商业价值。因此&#xff0c;前端性能的监控与优化已成为前端开发不可或缺的关键环节。本文将深入探讨从基础的性能评估工具L…

TC_Motion多轴运动-电子齿轮

目录 电子齿轮 【基本概念】 【应用示例】 【开发总结】 END 电子齿轮 【基本概念】 定义:通过软件方法实现机械齿轮的速比调节功能(两个轴成线性比例旋转) 优点 免维护,告别机械损耗 易调节,任意修改齿轮比 精度高,无机械背隙 应用场景 多台电机拖动同一负载,要求多台…

CentOS 7 下载教程

访问阿里云镜像站 阿里巴巴开源镜像站 选择centos 点这个 选择7版本 进入isos目录 点这个 选择这个版本 因为这个镜像的日期更新 推荐下载 DVD 版&#xff1a;包含完整系统和常用软件&#xff0c;无需额外联网安装组件Minimal 版&#xff1a;精简版&#xff0c;仅包含基础系…

MAC在home下新建文件夹报错“mkdir: test: Operation not supported”

在Mac电脑中&#xff0c;home文件夹下不能直接mkdir&#xff0c;sudo 也还是不行&#xff0c;提示“mkdir: test: Operation not supported”。网上找的解决方案不好使&#xff0c;因为没有关闭系统完整性保护关闭系统完整性保护查看SIP当前的状态csrutil status如果是开启状态…

交叉导轨从测试仪到工作台的精密运动控制

在精密仪器领域微米级的运动精度与纳米级的稳定性往往是决定设备性能上限的核心指标。而支撑这一技术鸿沟跨越的&#xff0c;往往隐匿于机械结构的“毫厘之间”——交叉导轨。以下是其在不同精密仪器中的具体应用&#xff1a;光学测试仪&#xff1a;光学测试仪主要用于各种高精…

内网穿透的应用-Navidrome与cpolar本地搭建跨网络访问的云音乐服务器

文章目录前言1. 安装Docker2. 创建并启动Navidrome容器3. 公网远程访问本地Navidrome3.1 内网穿透工具安装3.2 创建远程连接公网地址3.3 使用固定公网地址远程访问前言 音乐收藏存在平台版权限制、音质压缩和访问不便等问题。Navidrome 开源音乐服务器与 cpolar 内网穿透服务的…

FastAPI 访问不了API文档或配置不生效的解决方法

FastAPI中文教程 本文背景 FastAPI框架自带交互式api文档,通过路由/docs或者/redoc 访问&#xff0c;但是FastAPI 的文档界面&#xff08;如 /docs 和 /redoc&#xff09;依赖于外部的 JavaScript 和 CSS 库&#xff0c;如果项目部署环境网络不佳或者无法访问外网的时候&…

IAR 集成开发环境入门指南:字体设置与调试实战

一、IAR 的基本使用教程1. IAR 颜色字体大小设置打开设置路径&#xff1a;点击顶部菜单栏 Tools → 选择 Options&#xff0c;打开 IDE 配置窗口。进入字体颜色设置界面&#xff1a;在弹出的 “IDE Options” 窗口中&#xff0c;双击展开 Editor 选项&#xff0c;然后点击 Colo…

10:00开始面试,10:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%,这…

Flink 状态管理的核心能力

我们来看一个复杂的实际案例&#xff1a;阿里巴巴菜鸟的实时物流追踪系统。 该系统处理来自多个电商平台&#xff08;天猫、淘宝、速卖通&#xff09;的订单包裹&#xff0c;通过一个复杂的处理流程&#xff1a; 合并与去重&#xff1a;通过聚合操作将不同来源的订单合并并去重…

基于go语言的云原生TodoList Demo 项目,验证云原生核心特性

以下是一个基于 Go 语言 的云原生 TodoList Demo 项目&#xff0c;涵盖 容器化、Kubernetes 编排、CI/CD、可观测性、弹性扩缩容 等核心云原生特性&#xff0c;代码简洁且附详细操作指南&#xff0c;适合入门学习。项目概览 目标&#xff1a;实现一个支持增删改查&#xff08;C…

手机能看、投屏 / 车机不能看与反向链接验证类似吗?

有一定关联&#xff0c;但两者的技术逻辑并非完全等同 ——“手机能看、投屏 / 车机不能看” 的核心原因更复杂&#xff0c;反向链接验证是其中一种可能的限制手段&#xff0c;但不是唯一甚至不是最主要的手段。要理清这个问题&#xff0c;需要先拆解 “投屏 / 车机播放受限” …

25年9月通信基础知识补充1:NTN-TDL信道建模matlab代码(satellite-communications toolbox学习)

看文献过程中不断发现有太多不懂的基础知识&#xff0c;故长期更新这类blog不断补充在这过程中学到的知识。由于这些内容与我的研究方向并不一定强相关&#xff0c;故记录不会很深入请见谅。 【通信基础知识补充10】25年9月通信基础知识补充1&#xff1a;NTN-TDL信道建模matlab…

洛谷P3370 【模板】字符串哈希 (哈希表)详解

题目如下&#xff1a;&#xff08;注&#xff1a;解此题我只需左手一根指头&#xff0c;哈哈哈哈哈哈哈&#xff09;注意&#xff0c;哈希表的好处是能大幅度减少寻找遍历的时间可能有人不理解哈希值&#xff0c; 这里哈希的模的值一般得是比较大的质数&#xff0c;如标准的100…

光子芯片驱动的胰腺癌早期检测:基于光学子空间神经网络的高效分割方法(未做完)

光子芯片驱动的胰腺癌早期检测:基于光学子空间神经网络的高效分割方法 1 论文核心概念 本文提出了一种基于集成光子芯片的光学子空间神经网络(Optical Subspace Neural Network, OSNN),用于胰腺癌的早期检测与图像分割。其核心思想是利用光子芯片的高并行性、低延迟和低能…

GraphRAG 工作原理逐步解析:从图创建到搜索的实战示例

本篇文章How GraphRAG Works Step-By-Step: From Graph Creation to Search with Real Examples | Towards AI详细介绍了GraphRAG的工作原理&#xff0c;适合对检索增强生成&#xff08;RAG&#xff09;和知识图谱感兴趣的读者。文章的技术亮点在于通过图结构提升信息检索效率&…

LAMPSecurity: CTF8靶场渗透

LAMPSecurity: CTF8 来自 <https://www.vulnhub.com/entry/lampsecurity-ctf8,87/> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.168…