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

ceph的块存储如何骗过服务器,让服务器把它当做真实的硬盘

ceph的块存储就是一块远程网络硬盘。操作系统为啥会读写这块假硬盘呢一台服务器要使用CEPH提供的块存储也是需要ceph的驱动软件来和ceph通讯吧是的你的理解完全正确。一台服务器想要使用 Ceph 提供的块存储必须通过相应的“驱动软件”或客户端组件来和 Ceph 集群进行通讯。在 Ceph 的块存储RBD, RADOS Block Device体系中这种“驱动软件”主要分为两种实现路径1. 内核态驱动KRBD这是最常见、最接近传统硬盘使用习惯的方式。原理它依赖 Linux 内核自带的rbd模块rbd.ko。使用方式你需要在服务器上安装 Ceph 的客户端软件如ceph-common包然后使用rbd map命令将 Ceph 集群里的一个块设备镜像Image映射到本地。效果映射成功后你的服务器本地会出现一个标准的块设备文件例如/dev/rbd0。你可以像对待一块普通的物理硬盘一样对它进行分区、格式化如 mkfs.ext4并挂载到某个目录下使用。2. 用户态库librbd这种方式不通过内核而是直接在应用程序层面调用 Ceph 提供的动态链接库。原理应用程序直接链接并调用 Ceph 提供的librbd和librados库文件来读写数据。使用方式这种方式不会在操作系统里生成/dev/rbd0这样的设备文件而是由应用程序直接对接。典型场景主要被 KVM/QEMU 虚拟机或 OpenStack 等云平台使用。比如当你启动一台使用 Ceph 作为后端的虚拟机时宿主机上的 QEMU 进程就是通过librbd直接与 Ceph 集群通讯为虚拟机提供磁盘空间的。总结来说如果你是想把 Ceph 块存储当成一块普通的远程硬盘挂载到 Linux 服务器上你需要安装ceph-common客户端并依赖内核的KRBD 驱动如果你是开发应用程序或者配置 KVM 虚拟机来直接使用 Ceph 存储则是通过librbd 库来实现通讯的。自己实现一个最简的远程磁盘及协议要怎么做自己实现一个最简的远程磁盘系统核心原理其实就是**“网络IO”与“本地磁盘IO”的桥接**。简单来说就是把客户端Client对磁盘的读写请求通过网络发给服务端Server服务端在本地执行真实的读写操作后再把结果返回给客户端。我们可以把这个系统拆解为以下几个核心步骤来实现1. 通信层建立网络通道远程磁盘通常追求较高的读写性能因此底层通信协议一般首选TCP而不是 UDPTCP 能保证数据可靠传输避免磁盘数据丢包损坏。服务端启动一个 TCP 监听端口比如 8888等待客户端连接。客户端通过 IP 和端口连接到服务端建立一个稳定的长连接。2. 协议层设计“读写指令”为了让服务端听懂客户端要干什么我们需要自定义一个简单的通信协议报文格式。一个最简的远程磁盘协议只需要包含以下几种核心指令可以用一个字节来表示操作类型opcodeREAD读比如 opcode 0x01客户端告诉服务端“我要读数据”。WRITE写比如 opcode 0x02客户端告诉服务端“我要写数据”。ACK/RESPONSE应答服务端处理完后返回成功状态或读取到的数据。请求报文的结构可以设计得非常简单例如[操作码(1字节)] [偏移量 offset(8字节)] [数据长度 length(4字节)] [实际数据(写操作时附带)](注在网络传输多字节整数时记得使用大端序htons/htonl来保证不同架构机器间的兼容性。)3. 服务端实现本地磁盘的“代笔者”服务端的逻辑非常直观它本质上就是一个拿着“后端真实磁盘文件”的打工人在启动时服务端在本地创建一个巨大的空白文件比如disk.img用dd命令生成这个文件就代表一块“虚拟硬盘”。接收到客户端的READ请求后解析出offset偏移量和length长度使用系统调用如seek和read去读取disk.img对应位置的数据然后通过网络发回给客户端。接收到WRITE请求后解析出offset、length和附带的“实际数据”使用seek和write把数据精准地写入disk.img的对应位置。4. 客户端实现虚拟块设备驱动这是最难、也是最核心的一步。客户端不能只是一个普通的发请求的程序它必须让操作系统认为**“我插上了一块新硬盘”**。Linux 实现思路你需要编写一个 Linux内核模块利用 Linux 内核提供的ioctl接口。当客户端程序通过网络收到服务端发来的数据时通过ioctl把这些数据“喂”给内核的块设备层。这样Linux 系统里就会多出一个/dev/remote_disk0的设备文件。使用效果一旦这个设备文件出现你就可以像操作普通硬盘一样对它执行mkfs.ext4格式化然后mount挂载到某个目录随意读写文件。5. 进阶完善工程化细节当你把上面最简的“读写通路”跑通后一个真正可用的远程磁盘还需要考虑以下问题分包与粘包处理网络传输有 MTU最大传输单元限制大数据块需要拆分成小包发送并在协议头加上数据包的总长度防止接收方读取时发生粘包。断点续传与重试机制网络可能会抖动如果写入一半断网了需要有 ACK 确认机制和超时重传逻辑保证数据的一致性。权限与加密真实的远程磁盘不能谁都能连需要加上简单的身份验证甚至给 TCP 通道套上 TLS/SSL 加密防止数据在局域网内被窃听。总结一下实现一个最简远程磁盘本质上就是**“客户端内核驱动拦截IO请求 - 封装成自定义协议 - 走TCP网络发给服务端 - 服务端落地到本地大文件”**的完整闭环。这不仅是网络编程的硬核练手项目也能让你深刻理解 Ceph RBD、iSCSI 等成熟块存储产品的底层运作原理。linux驱动开发的原理和思路是什么请介绍的通俗易懂一些Linux 驱动开发的本质其实就是给操作系统写一个硬件的“专属翻译官”。因为硬件比如显卡、网卡、传感器只听得懂底层的电信号和寄存器指令而 Linux 内核和应用软件只懂标准的系统指令。驱动就是夹在中间的那层软件负责把上层的指令“翻译”成硬件能懂的操作再把硬件的反馈“翻译”回上层。为了让你更直观地理解我们可以把 Linux 驱动开发的原理和思路拆解为以下几个核心维度 核心思路一切皆文件这是 Linux 驱动开发最底层的哲学。在 Linux 看来不管是普通的文本文件还是键盘、鼠标、硬盘等硬件设备统统都被抽象成了一个“文件”。对用户来说操作硬件就像操作文件一样简单。比如你想点亮一个 LED 灯不需要去研究电路只需要向一个特定的设备文件比如/dev/led执行“写入”操作想读取温湿度传感器的数据只需要从这个设备文件里“读取”数据。对驱动来说你的工作就是写好这个“文件”背后的逻辑。你需要告诉系统当用户对这个文件执行open打开、read读、write写时驱动底层具体要去操作硬件的哪些寄存器、拉高还是拉低哪个引脚的电平。️ 核心模型总线-设备-驱动Bus-Device-Driver在早期的驱动开发中硬件信息和驱动代码经常混杂在一起导致代码极其难维护。现代 Linux 驱动开发采用了**“总线-设备-驱动”模型**核心思想就是**“分离与解耦”**。我们可以用**“开餐厅”**来打个比方设备Device就是**“食材”**比如鱼、肉、蔬菜它只负责描述硬件的客观属性比如硬件的内存地址、中断号等不包含任何处理逻辑。驱动Driver就是**“厨师”**比如王师傅只做鱼李师傅只做肉它只包含处理逻辑怎么切、怎么炒但不关心食材具体放在哪个冰箱里。总线Bus就是餐厅的**“调度员”**。它负责把“食材”和“厨师”匹配起来。开发思路变成了你只需要在代码里告诉内核“我是哪个总线的驱动我能处理哪种设备”内核的总线调度员就会自动帮你完成匹配。一旦匹配成功就会自动调用驱动里的初始化函数在代码中通常叫probe函数开始干活。️ 开发流程“三步曲”无论开发哪种驱动核心流程都可以简化为以下三个步骤“报名”——注册驱动在驱动模块加载时通过特定的注册函数告诉内核“嗨我来了我能管理某某硬件”“干活”——实现核心功能这是驱动的灵魂。你需要填充一个名为file_operations的结构体可以理解为一张任务清单把你的open、read、write等函数填进去。当用户程序调用系统指令时内核就会拿着这张清单精准地执行你写好的硬件操作代码。“卸任”——卸载驱动在驱动模块退出时负责释放占用的内存、注销设备把资源干干净净地交还给系统。 驱动家族的“三大门派”Linux 根据硬件传输数据的方式不同把驱动分成了三大类驱动类型核心特点典型代表字符设备驱动像水流一样按“字节”顺序传输不能随机乱跳键盘、鼠标、串口、各类传感器块设备驱动像集装箱运输按“块”如4KB批量传输支持随机读写硬盘、U盘、SSD也就是你刚才问的磁盘网络设备驱动专门处理网络数据包不走文件系统的 read/write 逻辑以太网卡、Wi-Fi 模块总结一下Linux 驱动开发就是利用**“一切皆文件”的哲学通过“总线-设备-驱动”**的解耦模型去编写一套标准化的代码填好file_operations这张表让操作系统能够统一、高效地指挥各种各样的硬件为你工作。驱动注册后设备从哪里来的驱动注册后“设备”的来源其实分为两个层面一个是物理上真实的硬件另一个是软件上供你调用的设备文件如/dev/xxx。我们可以结合你刚才了解的“总线-设备-驱动”模型来看看设备到底是从哪里“冒”出来的1. 物理设备从哪来硬件的“自我介绍”物理设备并不是驱动“变”出来的而是原本就存在的。驱动注册后内核会帮你在系统里“找到”这些设备。主要有两种情况热插拔发现即插即用当你把 U 盘、鼠标等 USB 设备插入电脑时硬件控制器会立刻感知到电压变化并向内核发送一个中断信号。内核收到信号后会马上读取这个新设备的描述符比如厂商 ID、产品 ID然后在系统内部登记“嘿总线上来了个新家伙”。系统启动枚举开机自检对于插在主板上的 PCIe、SATA 等固定设备系统在上电启动时内核的总线代码会主动去扫描物理总线把系统里所有的硬件设备都“点名”一遍登记在自己的花名册上。驱动注册后的动作当你调用xxx_driver_register()注册驱动时其实只是向内核提交了一份“简历”包含你能支持的设备 ID 等信息。内核会拿着你的简历去和它花名册上已经登记的设备进行匹配。一旦匹配成功内核就会自动调用你驱动里的probe探测函数相当于把硬件正式交到你手里去接管。2. 设备文件从哪来软件的“自动建档”物理设备被驱动接管后为了让用户空间也就是你的应用程序能方便地操作它系统还需要在/dev/目录下生成一个对应的设备文件比如/dev/sda或/dev/my_led。这个过程在现代 Linux 中是全自动的驱动“上报户口”在你的驱动代码通常在probe函数里接管硬件后会调用class_create()和device_create()这两个内核 API。这一步相当于驱动向系统大声汇报“我已经成功接管了这个硬件它的设备号是 XXX请给它建个档案”。内核“发广播”内核收到汇报后会在内部的sysfs文件系统/sys/class/目录里记录下这个设备的详细信息同时向用户空间发送一个名为uevent用户事件的广播通知。管家“自动建档”在用户空间有一个 7x24 小时值班的“管家”守护进程通常是udev在嵌入式系统中是它的精简版mdev。它时刻监听内核发出的uevent广播。一旦收到“有新设备加入”的通知它就会自动在/dev/目录下创建出对应的设备节点文件。简单总结一下驱动注册后物理设备是内核通过“扫描”或“监听中断”早就发现并登记好的而设备文件则是驱动在成功接管硬件后通过device_create()上报最终由系统里的udev/mdev管家自动在/dev/目录下创建出来的。请写一个最简单的驱动程序我学习一下结合你之前对“虚拟设备”和“驱动原理”的理解写一个最简单的 Linux 驱动最好的方式就是写一个**“虚拟内存字符设备”**。它的功能非常直观你在内核里开辟一块内存当作“虚拟设备”用户往里面写数据它就存起来用户读数据它就把存的内容返回给你。下面我们用大概 100 行代码带你一步步实现这个驱动。第一步编写驱动源码创建一个名为simple_char.c的文件把下面的代码复制进去#includelinux/init.h#includelinux/module.h#includelinux/fs.h#includelinux/cdev.h#includelinux/uaccess.h#includelinux/device.h#defineDEVICE_NAMEmy_virtual_dev// 设备名字#defineCLASS_NAMEmy_class// 设备类名字#defineBUFFER_SIZE1024// 虚拟内存缓冲区大小staticintmajor_num;// 主设备号staticstructclass*my_classNULL;// 设备类staticcharkernel_buffer[BUFFER_SIZE];// 模拟设备的内核内存// 1. 实现设备的 open 操作staticintmy_open(structinode*inode,structfile*file){pr_info(虚拟设备被打开啦\n);return0;}// 2. 实现设备的 read 操作把内核数据拷贝给用户staticssize_tmy_read(structfile*file,char__user*user_buf,size_tcount,loff_t*offset){intbytes_to_read;// 防止读取越界bytes_to_readmin(count,(size_t)(BUFFER_SIZE-*offset));if(bytes_to_read0)return0;// 安全地把数据从内核空间拷贝到用户空间if(copy_to_user(user_buf,kernel_buffer*offset,bytes_to_read)!0){return-EFAULT;}*offsetbytes_to_read;pr_info(给用户返回了 %d 个字节的数据\n,bytes_to_read);returnbytes_to_read;}// 3. 实现设备的 write 操作把用户数据拷贝给内核staticssize_tmy_write(structfile*file,constchar__user*user_buf,size_tcount,loff_t*offset){intbytes_to_write;bytes_to_writemin(count,(size_t)(BUFFER_SIZE-*offset));if(bytes_to_write0)return-ENOSPC;// 安全地把数据从用户空间拷贝到内核空间if(copy_from_user(kernel_buffer*offset,user_buf,bytes_to_write)!0){return-EFAULT;}*offsetbytes_to_write;pr_info(从用户那里接收了 %d 个字节的数据\n,bytes_to_write);returnbytes_to_write;}// 4. 填充文件操作结构体告诉内核我们实现了哪些功能staticstructfile_operationsfops{.ownerTHIS_MODULE,.openmy_open,.readmy_read,.writemy_write,};// 5. 驱动模块初始化函数驱动被加载时执行staticint__initsimple_char_init(void){// 动态申请一个主设备号major_numregister_chrdev(0,DEVICE_NAME,fops);if(major_num0){pr_err(申请主设备号失败\n);returnmajor_num;}// 创建设备类并在 /dev 下自动创建设备文件my_classclass_create(THIS_MODULE,CLASS_NAME);if(IS_ERR(my_class)){unregister_chrdev(major_num,DEVICE_NAME);pr_err(创建设备类失败\n);returnPTR_ERR(my_class);}device_create(my_class,NULL,MKDEV(major_num,0),NULL,DEVICE_NAME);pr_info(驱动加载成功主设备号是: %d\n,major_num);return0;}// 6. 驱动模块退出函数驱动被卸载时执行staticvoid__exitsimple_char_exit(void){device_destroy(my_class,MKDEV(major_num,0));// 销毁设备文件class_destroy(my_class);// 销毁设备类unregister_chrdev(major_num,DEVICE_NAME);// 释放主设备号pr_info(驱动已安全卸载\n);}module_init(simple_char_init);module_exit(simple_char_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(YourName);MODULE_DESCRIPTION(A Simple Virtual Character Driver);第二步编写 Makefile在同一个目录下创建一个名为Makefile的文件注意首字母大写没有后缀obj-m simple_char.o all: make -C /lib/modules/$(shell uname -r)/build M$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M$(PWD) clean第三步编译并运行测试你需要一台 Linux 电脑虚拟机或物理机均可打开终端进入这两个文件所在的目录依次执行以下命令编译驱动make编译成功后当前目录下会生成一个simple_char.ko文件这就是你的驱动模块。加载驱动需要管理员权限sudoinsmod simple_char.ko此时驱动已经运行在内核里了。你可以用ls /dev/my_virtual_dev看看系统已经自动帮你生成了这个设备文件。测试写入数据echoHello Linux Driver!|sudotee/dev/my_virtual_dev这行命令会把字符串写入你的虚拟设备驱动里的my_write函数会被触发。测试读取数据sudocat/dev/my_virtual_dev你会看到终端打印出Hello Linux Driver!这说明驱动里的my_read函数把刚才存在内核内存里的数据又还给了你。查看内核打印的日志dmesg|tail你会看到驱动里用pr_info打印的“虚拟设备被打开啦”、“接收了xx字节”等调试信息。卸载驱动sudormmod simple_char卸载后/dev/my_virtual_dev文件也会自动消失。通过这个最简的驱动你就完整走通了**“编写驱动代码 - 编译成模块 - 加载到内核 - 自动创建设备文件 - 用户空间读写测试 - 卸载驱动”**的整个 Linux 驱动开发闭环。你可以试着修改一下代码比如在write里加一些特殊的逻辑来加深对它的理解试了一下成功实现了一个最简驱动$ insmod simple_char.ko(gaofeng1120)$cat/dev/my_virtual_dev(gaofeng1120)$echoHello Linux Driver2!/dev/my_virtual_dev(gaofeng1120)$cat/dev/my_virtual_dev Hello Linux Driver2!simple_char.mod.c 是哪里来的为什会有这个文件simple_char.mod.c这个文件并不是你手写的而是Linux 内核构建系统Kbuild在编译过程中自动生成的临时文件。你可以把它理解为驱动模块的**“专属身份证”或“元数据说明文件”**。️ 它是怎么来的当你执行make命令编译驱动时内核的构建系统会按照以下流水线工作首先把你手写的simple_char.c编译成目标文件simple_char.o。紧接着构建系统会自动生成simple_char.mod.c并把它编译成simple_char.mod.o。最后链接器会把simple_char.o和simple_char.mod.o打包链接在一起生成最终的内核模块文件simple_char.ko。 为什么需要这个文件Linux 内核模块.ko和普通的应用程序不同它需要携带一些额外的“身份信息”才能被内核正确加载和识别。simple_char.mod.c的作用就是存放这些内核专属的元数据主要包括模块的许可证与描述信息把你代码里写的MODULE_LICENSE(GPL)、MODULE_AUTHOR、MODULE_DESCRIPTION等宏定义转换成内核能够识别的标准数据结构。模块的版本依赖Magic 校验记录当前模块是基于哪个版本的内核编译的。当你用insmod加载驱动时内核会检查这些信息防止你把一个为旧内核编译的驱动强行加载到新内核里从而避免系统崩溃即所谓的“版本魔术不匹配”。符号依赖信息如果你的驱动用到了其他内核模块导出的函数这些信息也会被记录在这里方便内核在加载时自动处理依赖关系。 里面到底写了什么如果你好奇完全可以打开simple_char.mod.c看一眼。你会发现它里面的代码非常枯燥基本全是自动生成的宏和结构体数组比如长这样仅作示意#includelinux/module.h#defineINCLUDE_VERMAGIC#includelinux/build-salt.h#includelinux/vermagic.h#includelinux/compiler.hBUILD_SALT;MODULE_INFO(vermagic,VERMAGIC_STRING);MODULE_INFO(name,KBUILD_MODNAME);__visiblestructmodule__this_module__section(.gnu.linkonce.this_module){.nameKBUILD_MODNAME,.initinit_module,#ifdefCONFIG_MODULE_UNLOAD.exitcleanup_module,#endif.archMODULE_ARCH_INIT,};总结一下simple_char.mod.c是编译内核模块时由系统自动生成的“中间产物”它负责把模块的身份信息和版本校验等元数据打包进最终的.ko文件里。你平时开发完全不用管它执行make clean时它也会被自动清理掉。没有看到makefile中调用kbuild啊 make -C /lib/modules/(shelluname−r)/buildM(shell uname -r)/build M(shelluname−r)/buildM(PWD) modules 这句话详细解释一下你观察得很仔细确实在这个Makefile里我们并没有直接写kmake这个词但你写的这句make -C ...实际上就是在调用 Linux 内核的构建系统也就是 Kbuild。在 Linux 内核开发中kbuild并不是一个独立的可执行程序的名字而是一整套构建规则和脚本的统称。这套规则的核心其实就是内核源码顶层目录下的那个Makefile。下面为你逐字逐句拆解这句核心命令make -C /lib/modules/$(shell uname -r)/build M$(PWD) modules1.make这就是 Linux 系统自带的标准 GNU Make 工具。2.-C /lib/modules/$(shell uname -r)/build-C这是标准make命令的一个选项意思是“Change Directory”切换目录。它会让make在执行任何操作之前先跳转到后面指定的那个目录里去。/lib/modules/$(shell uname -r)/build这是你当前运行的 Linux 系统的内核源码或内核头文件目录。$(shell uname -r)这是一个 Makefile 的语法它会执行系统命令uname -r来获取你当前的内核版本号比如5.15.0-76-generic。这个路径下通常有一个软链接指向了真正的内核源码或头文件目录。合起来的意思是让make工具暂时离开你当前的驱动目录带着内核顶层Makefile也就是 Kbuild 的核心规则去干活。3.M$(PWD)M这是专门传递给**内核顶层 MakefileKbuild**的一个特殊变量。它的作用是告诉内核的构建系统“虽然我切换到了内核目录但我真正要编译的模块源码其实是在M指定的这个目录里”。$(PWD)这也是 Makefile 的语法代表“Print Working Directory”当前工作目录也就是你存放simple_char.c和你的Makefile的这个文件夹。合起来的意思是告诉内核 Kbuild 系统编译完必要的依赖后请回到我这个驱动源码目录里把我的代码编译了。4.modules这是内核顶层 Makefile 里预定义好的一个编译目标Target。当你跳转到内核目录后执行make modules就会触发 Kbuild 里编译外部模块的整套复杂规则包括生成你刚才问的.mod.c文件、进行版本校验、最后链接成.ko等。 总结一下整个执行流程也就是 Kbuild 的“回调”机制你在驱动目录输入make你的Makefile开始执行。遇到make -C /内核目录 M$(PWD) modules。make带着指令跳转到了/内核目录找到了内核的顶层Makefile这时候 Kbuild 系统就被激活了。内核顶层Makefile看到M$(PWD)知道是要编译外部模块于是设置好各种复杂的环境变量和编译规则。内核顶层Makefile执行到modules目标时会**再次回调跳回**到你的驱动目录M指定的目录去读取你的obj-m simple_char.o并开始编译你的simple_char.c。编译完你的.o文件后Kbuild 系统会自动生成simple_char.mod.c并最终把所有东西打包链接成simple_char.ko。所以虽然你没看到kmake这个命令但通过make -C ... M... modules这种精妙的“跳转回调”机制你的驱动已经完整地享受了 Linux 内核 Kbuild 系统提供的全套专业编译服务

相关文章:

ceph的块存储如何骗过服务器,让服务器把它当做真实的硬盘

ceph的块存储,就是一块远程网络硬盘。操作系统为啥会读写这块假硬盘呢? 一台服务器要使用CEPH提供的块存储,也是需要ceph的驱动软件来和ceph通讯吧 是的,你的理解完全正确。一台服务器想要使用 Ceph 提供的块存储,必须…...

【tomcat部署前台war包报错】

tomcat部署前台war包报错 背景:tomcat启动前台war包,由zip直接改文件后缀成war包,jdk8 同事好使,我不好使 部署平台日志: 报错一、正常tomcat执行时会把war包解压成对应文件夹,这里应该是没解压成功。没有具…...

CANN-Ascend-C流水线编程-昇腾NPU上Cube和Vector怎么协作

CANN-Ascend-C流水线编程-昇腾NPU上Cube和Vector怎么协作 昇腾NPU的 AI Core 里有两种计算单元:Cube 做矩阵乘法,Vector 做逐元素运算。FlashAttention 这种融合算子需要 Cube 和 Vector 交替工作——先 Cube 算 QK^T,再 Vector 算 Softmax&a…...

2026 渗透测试行业全景解析|机遇、挑战与未来趋势

随着数字化转型的深入和网络威胁的日益复杂化,网络安全渗透测试行业在2025年迎来了前所未有的发展机遇与挑战。本文基于最新行业数据、招聘趋势与技术演进,全面剖析当前渗透测试行业的市场规模、人才供需、薪资水平、技术变革及未来发展方向,…...

网安从业者必学 100 个核心知识点,自查进阶必备

100条必背网络安全知识点,你都掌握了吗? 1988年,一款名为“莫里斯蠕虫”的程序悄然传播,它最初是康奈尔大学研究员的实验项目,目的是测量互联网规模。可谁也没想到,这个程序失控后感染了数千台电脑&#x…...

2026最新测评:4款海外降英文文本AIGC工具实测

我用GPT写了一篇英文技术报告,然后分别扔进4个降AI工具。结果出乎意料。如果你经常用ChatGPT、Claude或Gemini写英文内容——无论是论文摘要、技术文档、公司报告还是博客文章——你一定遇到过这个尴尬:明明内容是自己构思、自己修改的,但Tur…...

零基础学 Web 安全 20256最全系统入门攻略

“未知攻,焉知防”——真正的安全始于理解攻击者的思维 在日益数字化的世界中,Web安全工程师已成为企业防护体系的“数字盾牌”。本文将提供一条清晰的进阶路径,助你在2025年的网络安全领域脱颖而出。 一、认知篇:理解安全本质 …...

1分钟带你认识分辨率 帧率, 码率 HDR 的作用

日常刷视频,刷到关于剪辑的只是,就会老是听到一些分辨率,帧率 码率 HDR 这个名字,那你一定很好奇,这些是什么,有什么作用,今天小编就用最简单直白的话,一分钟带你搞懂四大核心参数的…...

龙芯LS2K PMON启动全解析:从内核到U盘识别的奥秘

【龙芯LS2K PMON终极干货】整机设备启动全景图:从 mainbus 开机到 U 盘识别全流程 一、整篇总纲(最强一句话) 内核启动 → 读 ioconf.c/cfdata 硬件族谱 → 从根总线 mainbus 开始遍历 → 逐级 attach 设备 → 启动 PCI → 扫描到 OTG 控制器 → 加载 dwc2 驱动 → 开启 U…...

实用购机指南:屏幕出色、流畅耐用续航拉满的手机

一、前言2026 年上半年,智能手机市场迎来新一轮旗舰迭代,用户购机核心需求已从单一参数比拼,转向流畅不卡顿、性能强劲、屏幕护眼优质、续航持久耐用的全能体验,同时兼顾影像创作与美学设计。为帮消费者精准筛选高适配机型&#x…...

微信聊天记录丢了怎么找回?这份教程很实用

你是否经历过这样的崩溃瞬间:手机清理空间时不小心删了微信聊天记录,或者重装微信后发现重要的对话全部消失?别慌,本文将系统梳理微信聊天记录丢失的常见原因,并提供多种经过验证的恢复方案,从微信官方自带…...

液压液水解安定性检测:核心原理与全行业应用场景解析

液压系统是各类工业、工程、交通设备的动力核心,而液压液作为系统的工作介质,其性能稳定性直接决定设备的运行精度、故障率以及使用寿命。在复杂工况中,水分侵入是导致液压液失效的核心诱因之一,油液遇水发生水解反应后&#xff0…...

Unity预加载:减少游戏中首次加载资源时的卡顿

遇到的问题&#xff0c;如标题所示&#xff0c;所以写了如下模块。模块功能就是初始化时候&#xff0c;加载零散/文件夹的物体&#xff0c;代码如下&#xff1a;#region 启动预加载模块/// <summary> 预加载间隔&#xff08;分帧防卡顿&#xff09; </summary>priv…...

从RSSI走向信道探测,蓝牙设备的“距离感知”能力已至“厘米级”

长期以来&#xff0c;物联网&#xff08;IoT&#xff09;无线连接技术的发展重心主要聚焦于通信性能、通信功耗与组网效率等方面&#xff1b;然而&#xff0c;随着智能家居、数字车钥匙、工业自动化、智慧门禁、资产管理以及地理围栏等应用的快速扩张&#xff0c;行业正在提出一…...

C++函数对象与仿函数

C函数对象与仿函数函数对象是重载了函数调用运算符operator()的类对象&#xff0c;也称为仿函数。它们可以像函数一样被调用&#xff0c;但比普通函数更灵活&#xff0c;可以保存状态和配置。函数对象的基本实现通过重载operator()实现。#include #include #includeclass Multi…...

【基于项目代码实测:XCP/CCP 模块“标定差异”全流程深度操作指南无标题】

在实际项目的 XCP/CCP 标定业务中&#xff0c;核对与同步底层内存参数是一项极其高频的操作。本指南将完全基于最新版“标定差异&#xff08;Calibration Difference&#xff09;”界面的真实功能逻辑&#xff0c;为你提供一份严谨、详细、且立即可用的三倍容量操作手册。无论你…...

AI应用可观测性工程:像监控微服务一样监控你的LLM应用

LLM 应用进入生产后&#xff0c;“为什么这次回答质量差&#xff1f;”、"哪次调用导致成本飙升&#xff1f;"这些问题如果没有完整的可观测性体系&#xff0c;根本无法回答。本文构建 LLM 应用的完整监控体系。LLM 应用监控的独特挑战传统微服务监控关注的是&#x…...

AI低代码产品,从“拖拽搭应用“到“对话即开发“,其中最关键的能力是什么?

作为一名在企业数字化一线摸爬滚打了10多年的项目负责人。这些年&#xff0c;我亲眼见证了低代码从小众工具变成企业标配的全过程。在2026年的当下&#xff0c;AI大模型现已全面融入低代码产品的底层&#xff0c;"对话生成应用"也已从概念名词变为了实际应用。但与此…...

主芯片LP3717BTT+LP3568C,5V3.1A过认证适配器⽅案(电路原理图)

LP3717BTT LP3568C 是一套 5V/3.1A&#xff08;15.5W&#xff09;隔离型反激电源方案&#xff0c;主打"过认证、高效率、低温度"。LP3717BTT 是原边 PWM 控制器&#xff0c;LP3568C 是次级同步整流芯片&#xff0c;两者配合实现高精度恒压输出&#xff0c;板端效率可…...

AI API 中转站完全指南:从 Claude、GPT 到“满血”“翻车”,一次搞懂整个 AI API 圈子

如果你刚开始接触 AI API&#xff0c;大概率会在各种开发者群、论坛或者教程里看到一堆让人摸不着头脑的词&#xff0c;比如“满血”“阉割”“翻车”“官转”“上车”“池子”“逆向”等等。很多新人第一次看这些内容的时候&#xff0c;基本都是每个字都认识&#xff0c;但连在…...

C 语言通讯录(终版)|新手踩坑全总结 + 最终可运行代码博客简介

系列回顾 本系列三篇完整闭环&#xff1a; 第一篇&#xff08;基础版&#xff09;&#xff1a;从零实现增删查改 文件存储&#xff0c;踩遍新手所有坑&#xff08;格式符乱码、文件闪退、输入死循环&#xff09;&#xff1b;第二篇&#xff08;优化版&#xff09;&#xff1…...

天勤策略钉钉告警:交易信号与异常通知怎么分流

前言 策略上云之后&#xff0c;我和同事最怕两件事&#xff1a;一是真出事了没人知道&#xff0c;二是没事也被钉钉刷屏刷到麻木。最早接推送时图省事&#xff0c;在 wait_update 里每次 last_price 变就发一条&#xff0c;一个活跃品种白天能几百条&#xff0c;两天之后群里全…...

LEFT JOIN 中 ON 与 WHERE 过滤的差异

在 MySQL 数据库开发中&#xff0c;LEFT JOIN&#xff08;左外连接&#xff09;是一个最常被误用的语法。许多开发者往往习惯性地将所有过滤条件一股脑地往 ON 后面塞&#xff0c;或者为了排版好看将条件全部扔到 WREHRE 里面。 这种模糊的逻辑在普通内连接&#xff08;INNER J…...

宇树go2机械狗远程操控联网问题

用手机“Unitree Go”app的wifi模式&#xff0c;让狗和电脑连接同一个wifi&#xff0c;使其处于同一个局域网下。要求wifi名和密码无中文。然后在本地电脑powershell输入ipconfig查询本机局域网网段&#xff0c;确认机械狗同一网段 IP 地址。终端执行命令&#xff1a;ssh unitr…...

如何找到最适合你的私有化IM?

跳出公有云的舒适区&#xff0c;决心搭建私有化IM&#xff0c;并不是一件能一蹴而就的事。市面上打着私有化旗号的软件鱼龙混杂&#xff0c;有的安装环境要求极高&#xff0c;有的功能华而不实。如何在复杂的选型迷雾中&#xff0c;找到最适合组织基因的那一款&#xff1f;你可…...

一幅精细绝伦的[城市或地点]微缩模型

提示词&#xff1a; 一幅精细绝伦的[城市或地点]微缩模型&#xff0c;无缝搭建于质朴的木桌之上&#xff0c;仿佛整个场景都是实时手工制作而成。场景囊括了[城市或地点]最具标志性的地标、建筑、街道、交通、文化元素和氛围&#xff0c;周围环绕着密 地址&#xff1a;https://…...

淮南家长必看:淮南哪里学少儿编程靠谱?原来这样选才不踩坑。

说实话&#xff0c;很多淮南家长送孩子学编程&#xff0c;心里是没底的。因为编程不像钢琴、画画&#xff0c;能当场弹一首或画一张给你看。孩子到底学了啥、学得怎么样&#xff0c;家长往往两眼一抹黑。今天我不推荐任何一家机构&#xff0c;只跟你分享三个普通人一眼就能看懂…...

2026年最佳手机阅读器推荐:付费也值得的精品选择

在数字时代&#xff0c;阅读方式正在发生深刻变革。随着电子书、在线文章和多媒体内容的兴起&#xff0c;人们越来越倾向于通过智能手机进行阅读。然而&#xff0c;并非所有的阅读器都能提供优质的阅读体验。今天&#xff0c;我们将聚焦于一款即便付费也绝对物超所值的手机阅读…...

DDD 中的代码组织:按技术层分 vs 按领域模块分,哪种才是正解?

前言 在实践领域驱动设计&#xff08;DDD&#xff09;时&#xff0c;你可能见过两种截然不同的代码组织方式&#xff1a;一种是传统的按技术层划分文件夹&#xff0c;另一种是按业务模块划分文件夹。两种写法的人都声称自己在做 DDD&#xff0c;那到底哪种更合理&#xff1f;本…...

从CDP“3A”到千亿美元目标:联想集团的创新路径与AI原生转型

在全球产业链加速重构、人工智能技术范式快速迭代的背景下&#xff0c;中国企业的创新能力正成为各界关注的焦点。当被问及“哪些中国企业创新做得不错”时&#xff0c;有一家科技企业凭借其在绿色低碳、供应链协同以及混合式人工智能领域的系统性突破&#xff0c;给出了具有说…...