2026年2月

厨房食品卫生安全检测数据集:智能餐饮与食品安全保障的视觉卫士

数据集分享链接

链接:https://pan.baidu.com/s/1rRHh2mJthhUAsNOrEGHxRg?pwd=r7q2

提取码:r7q2 复制这段内容后打开百度网盘手机App,操作更方便哦

一、智能餐饮与食品安全的时代背景

在餐饮行业中,食品卫生安全始终是重中之重。从厨房环境到工作人员行为,任何细节的疏忽都有可能带来食品安全隐患。食品安全问题不仅关系到消费者的健康,还关系到餐饮企业的声誉和生存发展。近年来,食品安全事件频发,给消费者带来了严重的健康威胁,也给餐饮企业造成了巨大的经济损失。

在传统餐饮管理中,食品安全监管主要依赖人工巡查和抽检,存在效率低下、覆盖面有限、易受人为因素影响等问题。人工巡查难以及时发现违规行为,抽检只能覆盖有限的时间和空间,难以及时发现食品安全隐患。因此,如何利用技术手段提高食品安全监管的效率和准确性,成为餐饮行业面临的重要挑战。

随着计算机视觉与人工智能技术的广泛应用,利用目标检测模型自动识别厨房安全风险成为可能。通过部署摄像头并结合AI算法,可以自动检测厨房中的违规行为,如厨师未戴帽子、未佩戴口罩、存在烟雾或垃圾溢出等问题,从而在源头保障食品安全。这种智能化的检测方式能够大幅提高食品安全监管的效率,降低监管成本,提升监管的准确性和及时性。

在智能餐饮领域,厨房食品卫生与安全检测技术能够优化餐饮管理,提升食品安全水平。通过实时监测厨房环境和工作人员行为,智能餐饮系统可以及时发现违规行为,提高食品安全监管的效率。同时,厨房食品卫生与安全检测技术还能够用于安全预警,为餐饮管理提供数据支持。

在食品安全监管领域,厨房食品卫生与安全检测技术能够优化食品安全监管,提升食品安全水平。通过实时监测厨房环境和工作人员行为,食品安全监管系统可以及时发现违规行为,提高食品安全监管的效率。同时,厨房食品卫生与安全检测技术还能够用于安全预警,为食品安全监管提供数据支持。

在公共卫生领域,厨房食品卫生与安全检测技术能够优化公共卫生管理,提升公共卫生水平。通过实时监测厨房环境和工作人员行为,公共卫生管理系统可以及时发现违规行为,提高公共卫生管理的效率。同时,厨房食品卫生与安全检测技术还能够用于安全预警,为公共卫生管理提供数据支持。

为了推动该方向的AI模型落地,我们整理并发布了一个厨房食品卫生与安全检测数据集(14类、18万张图片),专为目标检测任务(YOLO系列)设计,助力科研人员与企业快速构建实用的智能监控系统。

在这里插入图片描述

二、数据集核心特性与架构分析

该数据集包含18万张高质量图像,全面覆盖厨房环境中与卫生安全相关的场景与目标,共划分为14个检测类别。以下是该数据集的核心特性分析:

graph TD
    A[厨房食品卫生安全检测数据集] --> B[数据规模]
    A --> C[检测类别]
    A --> D[数据质量]
    A --> E[场景多样性]
    
    B --> B1[18万张图片]
    B --> B2[训练集151950张]
    B --> B3[验证集27850张]
    B --> B4[比例约5:1]
    
    C --> C1[人员行为]
    C --> C2[卫生状况]
    C --> C3[安全隐患]
    C --> C4[14个类别]
    
    D --> D1[YOLO格式标注]
    D --> D2[640x640尺寸]
    D --> D3[精准标注]
    
    E --> E1[真实厨房]
    E --> E2[合成图像]
    C --> E3[多场景覆盖]

2.1 数据集基本信息

数据集的基本信息如下:

项目说明
图像总量18万张
类别数量14个类别
训练集151950张(约84.5%)
验证集27850张(约15.5%)
训练集和验证集比例约5:1
标注格式YOLO标准TXT格式
图像尺寸640×640
任务类型目标检测(Object Detection)

2.2 检测类别定义

数据集共包含14个检测类别,分为人员行为、卫生状况、安全隐患三大类:

人员行为类别

人员行为类别是指厨房工作人员的行为规范,包括:发网、无手套、无帽子、有口罩、无口罩、电话、制服、帽子。人员行为是厨房卫生安全的重要检测对象,对于保障食品安全具有重要意义。人员行为的准确识别能够帮助系统及时发现违规行为,提高食品安全监管的效率。

卫生状况类别

卫生状况类别是指厨房环境的卫生状况,包括:蟑螂、老鼠、垃圾、垃圾桶。卫生状况是厨房卫生安全的重要检测对象,对于保障食品安全具有重要意义。卫生状况的准确识别能够帮助系统及时发现卫生问题,提高食品安全监管的效率。

安全隐患类别

安全隐患类别是指厨房环境的安全隐患,包括:烟雾、溢出。安全隐患是厨房卫生安全的重要检测对象,对于保障食品安全具有重要意义。安全隐患的准确识别能够帮助系统及时发现安全隐患,提高食品安全监管的效率。

三、数据集详细内容解析

3.1 数据集概述

该数据集包含18万张高质量图像,全面覆盖厨房环境中与卫生安全相关的场景与目标,共划分为14个检测类别。数据集中每张图像均配有精准标注,可直接用于训练YOLOv8、YOLOv5、DETR等主流检测模型。

类别信息
中文类别英文标注含义说明
蟑螂cockroach厨房中常见害虫,影响卫生
发网hairnet厨师佩戴的防护用品
无手套no_gloves操作食材时未佩戴手套
无帽子no_hat未佩戴厨师帽
老鼠rat厨房环境中的卫生隐患
有口罩with_mask正确佩戴口罩
无口罩without_mask未佩戴或口罩脱落
烟雾smoke炊事烟雾、燃烧气体
电话phone厨师操作中使用手机
溢出overflow食材或液体外溢
垃圾garbage厨房废弃物
垃圾桶garbage_bin固定垃圾存放点
制服chef_uniform规范的工作着装
帽子chef_hat正确佩戴厨师帽
数据划分情况
数据类型样本数占比
训练集(train)151950≈84.5%
验证集(valid)27850≈15.5%

数据集比例约为5:1,保证模型训练与验证的平衡性。

3.2 数据集详情

数据集在采集与标注阶段经过严格筛选,确保每类样本都具有代表性与多样性:

采集方式

包含真实厨房监控截图、合成图像与半监督增强样本。采集方式的多样性有助于模型学习适应不同场景的能力,提升模型的泛化能力。

图像尺寸

统一为640×640,支持YOLO系列模型直接输入。图像尺寸的统一性能够降低模型训练的复杂度,提高训练效率。

标注格式

YOLO标准TXT格式(class x_center y_center width height)。标注格式的标准化能够降低使用门槛,使更多研究者能够使用该数据集进行研究和开发。

配置文件

已提供data.yaml文件,结构清晰可直接加载。配置文件的提供能够降低使用门槛,使更多研究者能够使用该数据集进行研究和开发。

类别数量

14类完整映射。类别数量的完整性能够为模型训练提供全面的监督信号,提升检测性能。

文件结构示例
detect_kitchen/
├── train/
│   ├── images/
│   └── labels/
├── valid/
│   ├── images/
│   └── labels/
├── data.yaml
data.yaml示例
train: /path/to/detect_kitchen/train/images
val: /path/to/detect_kitchen/valid/images

nc: 14
names: [ 'cockroach','hairnet','no_gloves','no_hat','rat','with_mask','without_mask','smoke','phone','overflow','garbage','garbage_bin','chef_uniform','chef_hat' ]

在这里插入图片描述

在这里插入图片描述

四、数据集应用场景深度剖析

该数据集不仅适用于科研实验,也可直接用于商用AI系统开发,典型应用包括:

graph LR
    A[厨房食品卫生安全检测数据集] --> B[厨房卫生检测]
    A --> C[食品加工监控]
    A --> D[害虫监控报警]
    A --> E[安全防控]
    A --> F[教学竞赛]
    
    B --> B1[规范佩戴]
    B --> B2[行为识别]
    B --> B3[违规检测]
    
    C --> C1[实时检测]
    C --> C2[违规行为]
    B --> C3[视频监控]
    
    D --> D1[害虫检测]
    D --> D2[智能报警]
    B --> D3[卫生监控]
    
    E --> E1[烟雾检测]
    E --> E2[溢出检测]
    B --> E3[风险预警]
    
    F --> F1[AI教学]
    F --> F2[竞赛数据]
    B --> F3[研究支持]

4.1 厨房卫生检测系统

在厨房卫生检测系统领域,利用深度学习模型自动识别厨师是否规范佩戴帽子、口罩、手套。这是数据集在智能餐饮领域的重要应用。通过训练目标检测模型,可以实现对厨房工作人员行为的自动检测和识别。

在实际应用中,厨房卫生检测系统可以部署在厨房的监控设备上,实时采集厨房图像并进行工作人员行为分析。当检测到违规行为时,系统可以自动记录违规的时间、位置、人员等信息,并及时发出警报,提醒管理人员及时处理。这种自动检测方式大大提高了监控效率,降低了监控成本。

规范佩戴检测

通过检测厨师是否规范佩戴帽子、口罩、手套,识别违规行为。规范佩戴检测能够提高食品安全监管的效率,降低食品安全风险。

行为识别

通过识别厨师的行为,识别违规行为。行为识别能够提高食品安全监管的效率,降低食品安全风险。

违规检测

通过检测违规行为,提高食品安全监管的效率。违规检测能够提高食品安全监管的效率,降低食品安全风险。

4.2 食品加工车间视频监控

在食品加工车间视频监控领域,利用深度学习模型实时检测违规行为,如使用手机、垃圾溢出等。这是数据集在智能餐饮领域的重要应用。通过训练目标检测模型,可以实现对食品加工车间的自动监控和识别。

在实际应用中,食品加工车间视频监控系统可以部署在车间的监控设备上,实时采集车间图像并进行违规行为分析。当检测到违规行为时,系统可以自动记录违规的时间、位置、人员等信息,并及时发出警报,提醒管理人员及时处理。这种自动检测方式大大提高了监控效率,降低了监控成本。

实时检测违规行为

通过实时采集车间图像并进行违规行为分析,实现实时检测违规行为。实时检测违规行为能够及时发现违规行为,提高食品安全监管的效率。

使用手机检测

通过检测厨师是否使用手机,识别违规行为。使用手机检测能够提高食品安全监管的效率,降低食品安全风险。

垃圾溢出检测

通过检测垃圾是否溢出,识别卫生问题。垃圾溢出检测能够提高食品安全监管的效率,降低食品安全风险。

4.3 害虫监控与智能报警

在害虫监控与智能报警领域,利用深度学习模型检测蟑螂、老鼠等不卫生目标。这是数据集在智能餐饮领域的重要应用。通过训练目标检测模型,可以实现对厨房害虫的自动检测和识别。

在实际应用中,害虫监控与智能报警系统可以部署在厨房的监控设备上,实时采集厨房图像并进行害虫检测分析。当检测到害虫时,系统可以自动记录害虫的时间、位置等信息,并及时发出警报,提醒管理人员及时处理。这种自动检测方式大大提高了监控效率,降低了监控成本。

害虫检测

通过检测蟑螂、老鼠等害虫,识别卫生问题。害虫检测能够提高食品安全监管的效率,降低食品安全风险。

智能报警

当检测到害虫时,自动发出警报。智能报警能够及时提醒管理人员处理害虫问题,提高食品安全监管的效率。

卫生监控

通过检测害虫,监控厨房卫生状况。卫生监控能够提高食品安全监管的效率,降低食品安全风险。

4.4 安全防控

在安全防控领域,利用深度学习模型检测烟雾、溢出等火灾或泄漏风险。这是数据集在智能餐饮领域的重要应用。通过训练目标检测模型,可以实现对厨房安全隐患的自动检测和识别。

在实际应用中,安全防控系统可以部署在厨房的监控设备上,实时采集厨房图像并进行安全隐患检测分析。当检测到安全隐患时,系统可以自动记录安全隐患的时间、位置等信息,并及时发出警报,提醒管理人员及时处理。这种自动检测方式大大提高了监控效率,降低了监控成本。

烟雾检测

通过检测烟雾,识别火灾风险。烟雾检测能够提高安全防控的效率,降低安全风险。

溢出检测

通过检测溢出,识别泄漏风险。溢出检测能够提高安全防控的效率,降低安全风险。

风险预警

通过检测安全隐患,发出风险预警。风险预警能够及时提醒管理人员处理安全隐患,提高安全防控的效率。

4.5 AI教学与竞赛数据集

在AI教学与竞赛数据集领域,数据集非常适合目标检测、模型压缩、迁移学习等方向研究。这是数据集在学术研究领域的重要应用。通过使用数据集进行算法研究和性能对比,可以推动计算机视觉技术的发展。

在学术研究中,数据集可以用于验证新算法的性能,探索最优的模型架构。研究人员可以尝试不同的网络结构、损失函数、优化策略等,提升厨房食品卫生与安全检测的性能。

目标检测研究

使用数据集进行目标检测研究,验证新算法的性能。目标检测研究能够推动算法的进步和应用。

模型压缩研究

研究模型压缩技术,提升模型的推理速度。模型压缩研究能够推动算法的进步和应用。

迁移学习研究

研究迁移学习技术,提升模型的泛化能力。迁移学习研究能够推动算法的进步和应用。

五、YOLO目标检测训练示例

使用Ultralytics的YOLO框架,可以快速启动训练流程:

yolo detect train model=yolov8n.pt data=detect_kitchen/data.yaml batch=32 epochs=100 imgsz=640 device=cuda

5.1 参数说明

  • model=yolov8n.pt:选择轻量化模型
  • data=detect_kitchen/data.yaml:指定数据集配置
  • batch=32:每次训练的批次大小
  • epochs=100:训练轮数
  • imgsz=640:输入图像大小
  • device=cuda:启用GPU加速

5.2 训练输出结果示例

指标含义示例结果
mAP50平均准确率(IoU=0.5)0.89
mAP50-95多阈值平均准确率0.81
Precision精确率0.90
Recall召回率0.86

模型在验证集上表现优异,能够准确识别多种厨房安全隐患。

六、实践心得与经验总结

随着AI技术的成熟,智能食品安全检测正逐渐成为餐饮行业数字化升级的重要环节。本数据集的发布,旨在为开发者提供一个高质量、实用的研究基础,加速AI在食品安全、公共卫生监管、工业视觉等领域的应用落地。

在整理和使用这个厨房食品卫生与安全检测数据集的过程中,有以下几点体会:

6.1 数据规模的重要性

数据集包含18万张高质量图像,大规模数据能够为模型训练提供充足的样本,提升模型的泛化能力。数据规模的重要性在于能够为模型训练提供充足的监督信号,提升检测性能。

6.2 类别多样性的价值

数据集包含14个检测类别,涵盖人员行为、卫生状况、安全隐患等多个方面。类别多样性能够为模型训练提供全面的监督信号,提升检测性能。

6.3 标注精确性的重要性

数据集中每张图像均配有精准标注,标注精确性能够为模型训练提供准确的监督信号,提升检测性能。

6.4 数据划分的科学性

数据集按照标准比例划分为训练集和验证集,确保模型训练与评估的科学性。科学的数据划分能够确保模型训练与评估的独立性和可靠性。

6.5 食品安全应用价值的重要性

厨房食品卫生与安全检测技术具有重要的食品安全应用价值。通过自动检测厨房卫生与安全问题,可以及时发现违规行为和安全隐患,提高食品安全监管的效率。这种技术能够为食品安全提供有力支撑,推动智能餐饮的发展。

七、未来发展方向与展望

未来,我们将持续扩展场景类别,增加实时视频样本与实例分割标注,推动厨房智能检测系统向更高精度、更强鲁棒性发展。

数据集可以从以下几个方向进行扩展和优化:

一是增加更多样本数量,提升模型的泛化能力;二是增加更多类别,如更多种类的厨房卫生与安全问题,提供更全面的厨房卫生与安全描述;三是增加更多场景和环境的样本,如不同季节、不同天气条件、不同时间段等,提升模型的泛化能力;四是引入多模态数据,如视频数据、音频数据等,提供更丰富的厨房信息;五是添加实例分割标注,支持更精细的检测和分析。

此外,还可以探索数据集与其他食品安全数据集的融合,构建更全面的食品安全知识库。通过整合厨房数据、食品加工数据、食品安全数据等,可以构建更智能的食品安全决策支持系统,为食品安全和智能餐饮提供更强大的数据支撑。

随着人工智能技术的不断发展,厨房食品卫生与安全检测技术将朝着更高精度、更强鲁棒性、更智能化的方向发展。数据集作为技术发展的基石,将持续发挥重要作用,推动厨房食品卫生与安全检测技术的进步和应用落地。

八、数据集总结

数据集名称:厨房食品卫生与安全检测14类数据集

图片总数:18万张

任务类型:目标检测

推荐模型:YOLO / RT-DETR / Faster R-CNN

该数据集包含18万张高质量图像,全面覆盖厨房环境中与卫生安全相关的场景与目标,共划分为14个检测类别。

该数据集为AI研究者与开发者提供了一个高质量的厨房食品卫生与安全检测任务起点。无论你是刚入门的深度学习初学者,还是希望优化模型性能的研究者,该数据集都能助你快速构建高精度的检测系统。

通过本数据集,你可以快速构建出具有实际应用价值的检测模型,为后续的算法优化与项目部署打下坚实基础。未来,我们将持续更新数据集内容,拓展更多复杂场景与多类别标注,助力AI研究者在目标检测与食品安全领域取得更高成果。

前几天整理储存空间,清理出来几十个 G,然后这两天忙着过年拜年没空关注,昨天一看居然只剩下 13GB 了,有点懵。用 OmniDiskSweeper 来了全盘查,挨个文件夹查看,发现'/Users/username/Library/Application Support/dev.warp.Warp-Stable'这个路径下占了 30 多个 g ,点进去一看,密密麻麻的 dmg 文件,一开始还以为是用这个终端以来历次更新累计的,用了这个终端蛮多年了,就算是这样也很过分吧。再一看,创建时间从 2026 年 2 月 18 号开始,到今天上午为止还在创建,下面图里能看到创建时间,我都怀疑是不是偷偷用我电脑跑训练了。。。,还不知道怎么关这个东西。

CleanShot-2026-02-22-13-32-00@2x.png

在我敲下这些字的时候,我准备去 setting 中找找看有没有关掉更新的地方,被我逮到又在下载更新,此时距上次下载更新只过了 10 分钟。
image2.png
CleanShot-2026-02-22-13-31-23@2x.png

各位也可以检查看看有没有这个情况,我打算先停用一下这个终端了,除非找到怎么关闭自动更新。

 Microsoft Visual Studio(简称VS)是目前最流行的Windows平台应用程序的集成开发环境。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等。

一、准备工作

  1. 下载安装包安装包下载:https://pan.quark.cn/s/4b5cdf7b795c

二、安装Visual Studio 2022

  1. 解压安装包(若为压缩包):

    找到下载的安装包文件,右键点击 → 选择【解压到当前文件夹】(建议解压至非系统盘,如D盘,避免C盘空间不足)。

  2. 进入安装目录

    双击打开解压后的文件夹(通常命名为“VS2022”或类似)。

  3. 选择版本

    安装包内通常包含【企业版】和【专业版】,根据需求选择(新手推荐专业版,功能足够日常开发),双击对应版本的启动程序(如 vs_professional.exe)。

  4. 同意协议并继续

    弹出安装向导后,勾选“我同意许可条款和条件”,点击【继续】。

  5. 加载组件

    等待安装程序加载组件(进度条显示“正在准备下载页面”),约1-2分钟。

  6. 选择工作负载

    • 在“工作负载”选项卡中,勾选需要的开发组件(如:.NET桌面开发使用C++的桌面开发ASP.NET和Web开发等,按需选择,避免冗余);
    • 点击右侧【安装位置】选项卡,修改安装路径:

      • 修改安装路径:将默认路径首字符 C改为 D(如 C:\Program Files\Microsoft Visual Studio\2022\Professional→ D:\Program Files\Microsoft Visual Studio\2022\Professional);
      • 清理缓存:取消勾选“缓存安装文件”(缓存占用空间大,后续需用时可重新下载);
    • 确认路径修改后,点击【安装】。
  7. 等待安装完成

    安装进度条显示各组件下载与安装状态,耗时约10-30分钟(取决于网络和电脑性能),期间勿关闭窗口。

  8. 完成安装

    进度条满格后,点击【确定】。

三、启动与激活

  1. 重启电脑(可选)

    部分电脑会提示“需要重启以完成安装”,按提示重启后,点击任务栏【开始图标】→【所有应用】→ 找到并点击【Visual Studio 2022】启动。若未提示重启,直接执行下一步。

  2. 启动软件

    双击桌面或开始菜单中的“Visual Studio 2022”图标,启动软件。

  3. 跳过初始设置

    • 首次启动会显示“欢迎使用Visual Studio”,点击【暂时跳过此项】;
    • 进入主界面后,点击【启动Visual Studio】。
  4. 进入开发界面

    点击【继续但无需代码】(跳过创建项目的引导,直接进入空白开发环境)。

  5. 激活软件

    • 点击顶部菜单栏【帮助】→ 选择【注册Visual Studio】;
    • 在弹出的“注册”窗口中,点击【使用产品密钥解锁】;
    • 输入对应版本的产品密钥:

      • 专业版TD244-P4NB7-YQ6XK-Y8MMM-YWV2J
      • 企业版VHF9H-NXBBB-638P6-6JHCY-88JWH
    • 点击【应用】,提示“产品密钥已成功应用”即激活完成。

四、安装完成

至此,Visual Studio 2022已成功安装并激活,可正常使用全部功能。

让它帮忙接着 codex 的工作去总结文档。

偷空看了一眼,这家伙满嘴俏皮话,屁话一堆,一点都不严谨整洁,完全废掉了。还得重新总结。

就类似下面的文字风格,默认的,完全没有做额外的提示:

“1. **骨灰级的身份烙印标识标**:在极老极为远古 Unix 天皇老子辈时代它这本就是极有这作为被当来派做辨认每台这长相差极大不齐不各物理机的唯一极核心身份凭牌用来用以标识用去授权与这极老网络发证所极大极大之依靠去挂所本底了。
2. **极道唯一假像极长防线弱极大虚标识**:在现代世界里由于大家全是虚拟机云底云起发,这是极其极不极其极其靠不住极大可能会一样极极其可能极相撞的一段极大破弱的极虚弱极标记串底壳标号牌而已。”

属实无语。


📰 内容说明:本文为 AI 资讯摘要与编辑评论,所有内容均已标注原文链接。如涉及版权问题请联系处理。


今日亮点

今天 AI 圈热闹非凡。内存市场因为中国厂商 CXMT 的半价 DDR4 芯片掀起波澜,这不仅是价格战,更牵动着全球 AI 算力供应链的神经。与此同时,围绕 AI Agent 的讨论和实践持续升温,从渗透测试到科学研究,Agent 正在变得更自主、更专业。就连 Claude 这样声称“代码免费”的 AI,桌面应用却仍是 Electron,引发了关于 AI 生成代码与实际工程落地之间权衡的思考。

💡 产品动态

Claude 桌面版仍是 Electron 应用,引发“代码免费”争议

Anthropic 的 Claude 桌面版应用被发现仍采用 Electron 框架,这在“AI 能生成代码”的背景下引发了关于技术栈选择、工程成本与实际用户体验的讨论,用户抱怨其资源占用和功能缺失。

💡 编辑观点: 这揭示了 AI 生成代码和高质量软件工程之间的现实鸿沟。即便 AI 能提高编码效率,但跨平台开发中的性能优化、资源管理和用户体验打磨,仍是需要大量人工智慧和工程权衡的复杂任务,远非“代码免费”就能解决。

📎 查看完整报道 | 来源: News Hacker

Zclaw 项目声称实现 ESP32 上的 888KB 个人 AI 助理

Zclaw 项目宣称能在 Espressif 的 ESP32 微控制器上,以小于 888KB 的固件大小实现个人 AI 助理,但其“板载推理”的真实性和在低功耗设备上处理敏感任务的隐私安全性引发了社区的质疑。

💡 编辑观点: 这是一个探索边缘 AI 与嵌入式设备潜力的有趣尝试。尽管在微控制器上运行 AI 模型令人兴奋,但实际应用中必须正视硬件算力、内存限制以及数据隐私安全问题。过度依赖小设备处理敏感信息,可能带来比想象中更大的风险。

📎 查看完整报道 | 来源: News Hacker

🔬 学术前沿

突破黑盒 LVLM 攻击:M-Attack-V2 通过细粒度细节定位实现更高成功率

新研究提出 M-Attack-V2,通过多裁剪对齐和辅助目标对齐,显著提升了对 Claude-4.0、Gemini-2.5-Pro 和 GPT-5 等前沿多模态大模型的黑盒对抗攻击成功率,最高可达 100%。 → 📄 阅读论文

通过 Bloom 分类法线性探测 LLM 认知复杂性

研究发现,利用 Bloom 分类法,可以通过线性探测 LLM 内部的激活向量,以 95% 的平均准确率区分不同认知复杂度的任务(从记忆到创造),表明 LLM 在转发过程中早期就编码了提示的认知难度。 → 📄 阅读论文

NeuDiff Agent:AI 工作流加速中子晶体学研究

NeuDiff Agent 是一个由 AI 驱动的工作流,旨在加速单晶中子晶体学分析,将手动分析时间从 435 分钟缩短到约 90 分钟,同时保证结果的准确性和可追溯性,展示了 AI Agent 在科学发现中的巨大潜力。 → 📄 阅读论文

Texo:仅 20M 参数的高性能公式识别模型

Texo 模型仅有 2000 万参数,但其在公式识别方面达到了与最先进模型媲美的性能,同时将模型尺寸减小 80% 以上,使其能够在消费级硬件甚至浏览器中进行实时推理。 → 📄 阅读论文

🌍 行业观察

中国内存厂商 CXMT 以大约市场价一半的价格出售 DDR4 芯片,这一举动引发了市场对国家补贴、供应链风险以及西方厂商将产能转向 HBM 等高端产品战略的激烈讨论。

💡 编辑观点: 这场突如其来的价格战,远不止商业竞争那么简单。它折射出全球半导体产业在 AI 时代下,地缘政治、技术路线选择和供应链安全等多重考量。西方厂商押注 HBM 等高利润 AI 内存,可能暂时放弃 DDR4 市场份额,但长期来看,关键商品产能集中化可能带来战略脆弱性,为全球 AI 算力基础设施的未来发展埋下伏笔。

📎 深度报道

💻 开源项目

  • pentagi (⭐ 趋势榜):完全自主的 AI 智能体系统,能够执行复杂的渗透测试任务 → 🔗 GitHub
  • claude-code (⭐ 趋势榜):Anthropic 的智能编程工具,可在终端运行,通过自然语言协助编码和 Git 工作流 → 🔗 GitHub
  • GitNexus (⭐ 趋势榜):零服务器代码的客户端知识图谱创建器,可从 GitHub 仓库或 ZIP 文件构建内置 Graph RAG 代理的交互式知识图谱 → 🔗 GitHub
  • ggml (⭐ 趋势榜):一个 C/C++实现的机器学习张量库,常用于在各种硬件上高效运行大模型 → 🔗 GitHub

💬 社区热议

  • AI 研究倾向性引争议: Ethan Mollick 观察到,关于“AI 会失败”或“模型崩溃”的论文总能引发热议,而“AI 表现出色”的论文却关注度不高,这可能反映了公众对 AI 的深层不安。 → 来源: Twitter (Ethan Mollick)
  • Hinglish LLM 合成数据质量挑战: 一位开发者在构建印地语+英语(Hinglish)LLM 的合成数据引擎时,质量分数仅为 0.69,正寻求社区关于是否值得继续优化或统计合成数据是否已走到尽头的建议。 → 来源: Reddit (r/MachineLearning)
  • Qwen3-TTS 在 Mac 本地流畅运行: Qwen3-TTS 在 Mac 本地通过 MLX 框架运行 WebUI,实现了非常流畅的语音合成效果,引发用户对其在 Apple Silicon 设备上原生性能的赞叹。 → 来源: Twitter (shing)

用了好多年苹果,这过年了媳妇给买了一个三星 fold7 ,之前主要在用 iphone14pro + watch ultra2 ,日常主要是 google 全家桶和苹果原生的软件(备忘录 提醒 日程之类的),换了三星之后也没什么影响,目前主要比较难受的是手表没法用了,虽然是蜂窝版也开了一号双终端,但是独立使用功能是不全的,又不想整天带着俩手机,有点难受。



ps:刷了港版系统还不错。

HP LoadRunner 12.53 Community Edition - Standalone Applications.exeLoadRunner 12.53 社区版​ 的独立安装包,LoadRunner 是做性能测试的工具,能模拟成千上万用户同时访问网站、接口、应用,看系统会不会卡、崩,做压力测试、负载测试基本离不开它。

社区版是免费的,功能够个人学习用,下面用大白话一步步说安装过程,跟着做就能装上。

一、准备工作

  1. 下载安装包

    • 安装包下载:https://pan.quark.cn/s/d3f68aa36415 ,注意是 Community Edition(社区版) ,别下成付费企业版。
    • 文件比较大,几个 GB,下载时耐心等。
  2. 确认系统版本

    • 支持 Win7/Win10(32 位和 64 位都行),但建议 64 位系统,性能测试时更稳。
  3. 用管理员身份运行(必须)

    • 右键安装包 → 选“以管理员身份运行”,否则很多组件装不上。

二、安装步骤

  1. 双击 HP LoadRunner 12.53 Community Edition - Standalone Applications.exe运行(如果右键过了就直接双击)。
  2. 第一次打开会弹出“用户账户控制”提示 → 点  “是”
  3. 进入安装向导,选语言(默认 English,有的版本有中文)→ 点  “Next”
  4. 阅读许可协议 → 选 “I accept the terms in the License Agreement” → 点  “Next”
  5. 选安装类型:

    • 社区版一般选 Typical(典型安装) ​ 就行,会把常用组件装好;
    • 想自己选就选 Custom(自定义),但新手不建议乱改。
  6. 选安装位置:

    • 默认是 C:\Program Files\HP\LoadRunner,可点 Browse 改到其他盘(比如 D 盘)。
  7. 点  “Install” ​ 开始安装,等进度条走完(可能要十几分钟,看电脑配置)。
  8. 安装完会问是否立即启动 → 可先取消,等会儿再开。

三、首次运行与基本使用

  1. 在开始菜单或桌面找到 HP LoadRunner​ → 点开,一般会有 LoadRunner Controller、Virtual User Generator(VuGen)等入口。
  2. 创建测试脚本

    • 打开 VuGen → 新建脚本,选协议(比如 Web - HTTP/HTML、Web Services、Java Vuser 等)→ 点 “Create”。
    • 在脚本里录制或编写操作步骤,比如打开网页、登录、查询。
  3. 设计场景

    • 打开 Controller → 导入脚本 → 设置并发用户数、运行时间、负载生成器等参数。
  4. 运行测试

    • 点 “Start Scenario” 开始压测,看响应时间、吞吐量、错误率等指标。
  5. 分析结果

    • 测试结束后,Controller 会生成报告,或者用 Analysis 工具分析数据,看系统性能瓶颈。

Zotero7.0.8是 Zotero 7.0.8 版本​ 的 Windows 安装包,Zotero 是个文献管理工具,主要用来收集、整理、引用论文、书籍、网页等资料,写论文、做科研、写报告都能用,尤其是需要自动生成参考文献的时候特别省事。

装起来不复杂,下面用大白话一步步说,跟着做就能装上。

一、准备工作

  1. 下载安装包

  2. 用管理员身份运行(推荐)

    • 右键 Zotero7.0.8.exe→ 选“以管理员身份运行”,避免权限不足导致安装失败。

二、安装步骤

  1. 双击 Zotero7.0.8.exe运行(如果右键过了就直接双击)。
  2. 第一次打开会弹出“用户账户控制”提示 → 点  “是”
  3. 进入安装向导,选语言(默认 English,有的版本有中文)→ 点  “Next”
  4. 阅读许可协议 → 选 “I accept the terms in the License Agreement” → 点  “Next”
  5. 选安装位置:

    • 默认是 C:\Program Files\Zotero,可点 Browse 改到其他盘(比如 D 盘)。
  6. 附加任务:

    • 建议勾 “Create a desktop shortcut”(创建桌面快捷方式),方便以后打开。
  7. 点  “Install” ​ 开始安装,等进度条走完(一两分钟)。
  8. 安装完会问是否立即启动 → 可先取消,等会儿再开。

三、首次运行与基本使用

  1. 在开始菜单或桌面找到 Zotero​ → 点开。
  2. 第一次打开会让你注册/登录 Zotero 账号(注册免费),登录后能同步文献到云端,换电脑也不怕丢。
  3. 添加文献

    • 点左上角 “+” 号,选 “从网页抓取”(装了浏览器插件后,在知网、Google Scholar 等网站点插件图标就能直接存文献)。
    • 或者手动点 “通过标识符添加”,输入 DOI 或 ISBN 号,Zotero 会自动拉取文献信息。
  4. 整理文献

    • 在左侧文件夹里建分类,把文献拖进去。
    • 可以加标签、写笔记,方便以后找。
  5. 引用文献

    • 在 Word 里装 Zotero 插件,写论文时选好格式,点 “插入引文” 就能自动生成参考文献列表。

表示一个按排序顺序维护的对象集合。

public class SortedSet < T > : System . Collections . Generic . ICollection < T > , System . Collections . Generic . IEnumerable < T > ,  System . Collections . Generic . IReadOnlyCollection < T > ,  System . Collections . Generic . IReadOnlySet < T > ,  System . Collections . Generic . ISet < T > ,  System . Collections . ICollection ,  System . Runtime . Serialization . IDeserializationCallback ,  System . Runtime . Serialization . ISerializable

参数

参数类型注解
T泛型参数集合中的元素类型

继承

ObjectSortedSet

实现

ICollection < T >,IEnumerable < T >,IReadOnlyCollection < T >,ISet < T >,ICollection,IEnumerable,IReadOnlySet < T >,IDeserializationCallback,ISerializable

示例

以下示例演示了一个 SortedSet < T > 类,该类通过接受 IComparer < T > 作为参数的构造函数创建。此比较器(ByFileExtension)用于按扩展名对文件名列表进行排序。

using System . Collections;

try
    {
    DirectoryInfo WJJ1 = new ( Environment . GetFolderPath ( Environment . SpecialFolder . MyDocuments ) );
    IEnumerable < FileInfo > WJs1 = WJJ1 . EnumerateFiles ( "*" , SearchOption . TopDirectoryOnly );
    SortedSet < FileInfo > WJs1图像 = new ( new LEI按文件扩展名 ( ) );
    foreach ( FileInfo wj in WJs1 )
        {
        Console . WriteLine ( wj . FullName );
        WJs1图像 . Add ( new FileInfo ( wj . FullName [ ( wj . FullName . LastIndexOf ( '\\' ) + 1 ) .. ] ) );
        }
    Console . WriteLine ( "在列表中移除文档……" );
    Console . WriteLine ( $"\t移除文档前……{WJs1图像 . Count}" );
    WJs1图像 . RemoveWhere ( FF是文档 );
    Console . WriteLine ( $"\t移除文档后……{WJs1图像 . Count}" );

    FileInfo? wj1 = null , wj2 = null;
    SortedSet < FileInfo > JPGs = WJs1图像 . GetViewBetween ( wj1 , wj2 );
    Console . WriteLine ( "图像文件:" );
    foreach ( FileInfo T in JPGs )
        {
        Console . WriteLine ( T . Name );
        }
    }
catch ( IOException ioEx )
    {
    Console . WriteLine ( ioEx . Message );
    }

catch ( UnauthorizedAccessException AuthEx )
    {
    Console . WriteLine ( AuthEx . Message );
    }


static bool FF是文档 ( FileInfo 文件 )
    {
    string 文件名 = 文件 . FullName . ToLower ( );
    return ( 文件名 . EndsWith ( ".txt" ) ||
            文件名 . EndsWith ( ".xls" ) ||
            文件名 . EndsWith ( ".xlsx" ) ||
            文件名 . EndsWith ( ".pdf" ) ||
            文件名 . EndsWith ( ".doc" ) ||
            文件名 . EndsWith ( ".docx" ) ) ||
            文件名 . EndsWith ( ".ini" ) ||
            文件名 . EndsWith ( ".dwg" ) ||
            文件名 . EndsWith ( ".accdb" );
    }

public class LEI按文件扩展名 : IComparer < FileInfo > , IComparer < string >
    {
    string? kz1 , kz2;
    private readonly CaseInsensitiveComparer BJQ不区分大小写 = new ( );

    public int Compare ( FileInfo? x , FileInfo? y )
        {
        if ( x == null || y == null ) return 0;
        kz1 = x . Extension;
        kz2 = y . Extension;

        // 比较两个文件的扩展名
        int z = BJQ不区分大小写 . Compare ( kz1 , kz2 );
        if ( z != 0 )
            {  return z; }
        else // 扩展名相同则比较文件名
            { return BJQ不区分大小写 . Compare ( x . Name , y . Name ); }
        }

    public int Compare ( string? x , string? y )
        {
        if ( x == null || y == null ) return 0;
        kz1 = x [ ( x . LastIndexOf ( '.' ) + 1 ) .. ];
        kz2 = y [ ( y . LastIndexOf ( '.' ) + 1 ) .. ];
        int z = BJQ不区分大小写 . Compare ( kz1 , kz2 );
        if ( z != 0 )
            { return z; }
        else
            { return BJQ不区分大小写 . Compare ( x , y ); }
        }
    }

备注

SortedSet < T > 对象可在插入和删除元素时维持排序顺序,且不会影响性能。不允许有重复元素。不支持更改现有项的排序值,这可能会导致意外行为。

关于集和集合

集可以用于描述 Collection,其内部可能是多种类型、没有顺序、可能重复的元素。而集合,即 Set,用于单类型、可以排序、可以去重的列表。

集可类比你逛大街,卖啥的都有,例如几家卖包子的;集合可类比你进了一家包子铺,商品琳琅满目,但都是包子,而且可能给你照食材、价格等因素排列好(SortedSet 会排序,HashSet 不会),但一定是一种包子一个食盘,挑着吃就是了。

构造函数

名称描述
SortedSet < T > ( )初始化 SortedSet < T > 类的新实例
SortedSet < T > ( IComparer < T > )初始化使用指定比较器的 SortedSet < T > 类的新实例
SortedSet < T > ( IEnumerable < T > )初始化包含从指定可枚举集或集合复制的元素的 SortedSet < T > 类的新实例
SortedSet < T > ( IEnumerable < T > , IComparer < T > )初始化 SortedSet < T > 类的新实例,该实例包含从指定的可枚举集或集合复制的元素,并使用指定的比较器

备注

此构造函数是一个 O(1)操作。

public SortedSet ( );
public SortedSet ( System . Collections . Generic . IComparer < T >? 比较器 );
public SortedSet ( System . Collections . Generic . IEnumerable < T > 集或集合 );
public SortedSet ( System . Collections . Generic . IEnumerable < T > 集或集合 , System . Collections . Generic . IComparer < T >? 比较器 );

参数

参数类型注解
比较器IComparer比较对象的 比较器
集或集合欲复制到 SortedSet 中的元素的集或集合

异常

异常注解
ArgumentNullException比较器 或 集或集合 是 null

示例

基础示例中,已经展示了使用 比较器 产生新的 SortedSet 的方式,下面的示例使用已存在的集合创建新的 SortedSet:

IEnumerable < int > ZHSs = [ 3 , 1 , 0 , -3 , 7 ];
SortedSet < int > ZHSs排序 = [ .. ZHSs ];
foreach ( int z in ZHSs排序 )
    {
    Console . Write ( $"{z}\t" );
    }

备注

当无需从 集或集合 中复制元素并排序,方法是个 O(1)操作;否则方法是个 O(n × log ( n ))操作,n 是 集或集合 中的元素数量。

被复制到 SortedSet 中的元素不会是重复的,即使 集 中有重复元素,且不会抛出异常。

属性

Comparer

获取用于对 SortedSet < T > 中的值进行排序的 IComparer < T > 对象。
public System . Collections . Generic . IComparer < T > Comparer { get; }

属性值

类型注解
Icomparer < T >用于对 SortedSet < T > 中的值进行排序的比较器

备注

返回的比较器可以是 SortedSet < T > 类型的默认比较器,也可以是其构造函数所使用的比较器。

检索此属性的值是一个 O(1)操作。

Count

获取 SortedSet < T > 中的元素的数量。
public Int Count { get; }

属性值

类型注解
Int32SortedSet < T > 中的元素的数量

实现

Count ( )

备注

检索此属性的值是一个 O(1)操作。

Max 和 Min

获取由比较器定义的 SortedSet < T > 中的最大值或最小值。

public T? Max { get; }
public T? Min { get; }

属性值

类型注解
TSortedSet < T > 中的元素的最大值或最小值

备注

如果 SortedSet < T > 不包含任何元素,则 Max 或 Min 属性会返回 T 的默认值。

方法

Add 和 Remove

向集合添加或删除一个元素,并返回一个值,该值指示是否成功添加或删除了该元素。

public bool Add ( T 项目 );
public bool Remove ( T 项目 );

返回值

类型注解
bool当添加(Add)元素或移除(Remove)元素成功时,会返回 true;否则返回 false

示例

IEnumerable < int > ZHSs = [ 3 , 1 , 0 , -3 , 3 , 7 ];
SortedSet < int > ZHSs排序 = [ .. ZHSs ];
foreach ( int z in ZHSs排序 )
    {
    Console . Write ( $"{z}\t" );
    }
Console . WriteLine ( );

ZHSs排序 . Add ( 9 );
ZHSs排序 . Remove ( 7 );
ZHSs排序 . Add ( 3 );
ZHSs排序 . Remove ( -1 );

foreach ( int z in ZHSs排序 )
    Console . Write ( $"{z}\t" );

备注

SortedSet < T > 类不接受重复元素。如果 项目 已在集合中,Add 方法会返回 false 且不会抛出异常。

如果计数已等于 SortedSet < T > 对象的容量,则会自动调整容量以容纳新项。

如果 SortedSet < T > 对象不包含指定元素,则移除该对象的元素该对象保持不变,且不会抛出异常。

对于引用类型,项目 可以为 null。

Remove 方法是一个 O(log ( n))操作。

Clear

在 SortedSet 中移除所有元素。
public virtual void Clear ( );

实现

Clear ( )

备注

此方法是一个 O(n)操作,其中 n 为 SortedSet . Count。

Contains

确定 SrotedSet 中是否包含特定元素。
public virtual bool Contains ( T 项目 );

参数

参数类型注解
项目T泛类型的 集合 中欲查找的元素

返回值

类型注解
bool集合 中是否包含欲查找的元素的 bool

实现

Contains ( )

备注

此方法是一个 O(log ( n ))操作。

CopyTo

将 SortedSet < T > 的一部分或全部复制到兼容的一维数组中,从目标数组的开头或指定索引处开始。

重载

重载注解
CopyTo ( T [ ] )将 SortedSet 的全部元素复制到兼容的一维数组中
CopyTo ( T [ ] , Int32 起始索引 )将 SortedSet 的全部元素复制到兼容的一维数组中(自起始索引起)
CopyTo ( T [ ] , Int32 起始索引 , Int32 元素数 )将 SortedSet 的部分元素(指定元素数)复制到兼容的一维数组中(自起始索引起)
public void CopyTo ( T [ ] 数组 );
public void CopyTo ( T [ ] 数组 , int 起始索引 );
public void CopyTo ( T [ ] 数组 , int 起始索引 , int 元素数 );

参数

参数类型注解
数组T [ ]容纳 SortedSet 元素的一维数组,必须是以 0 索引起始的
起始索引Int32数组 的起始索引,复制从此开始
元素数Int32复制的元素数

实现

CopyTo ( T [ ] , Int32 )

异常

异常注解
ArgumentException数组 或 数组 自 起始索引 起,剩余空间不足以容纳 SortedSet 中的元素
ArgumentNullException数组 是 null
ArgumentOutOfRangeException起始索引 或 元素数 小于 0

备注

数组 必须是一维的,以 0 为起始索引的,且能容纳 SortedSet 元素类型的数组。

复制一定是自 SortedSet 启始元素开始,复制整个 SortedSet 或指定 元素数 为止。起始索引 只和目标数组有关。因为 SortedSet 没有索引器。

此方法是一个 O(n)操作,其中 n 为 SortedSet 的 Count 或指定 元素数。

CreateSetComparer

返回一个 IEqualityComparer 对象,该对象可用于创建包含各个 SortedSet 的集合。

重载

重载注解
CreateSetComparer ( )返回一个 IEqualityComparer 对象,该对象可用于创建包含各个 SortedSet 的集合
CreateSetComparer ( IEqualityComparer < T > )根据指定的比较器返回一个 IEqualityComparer 对象,该对象可用于创建包含各个 SortedSet 的集合
public static System . Collections . Generic . IEqualityComparer < System . Collections . Generic . SortedSet < T > > CreateSetComparer ( );
public static System . Collections . Generic . IEqualityComparer < System . Collections . Generic . SortedSet < T > > CreateSetComparer ( System . Collections . Generic . IEqualityComparer < T >? 成员相等比较器 );

参数

参数类型注解
成员相等比较器IEqualityComparer < T >用于创建返回的比较器的比较器

返回值

类型注解
IEqualityComparer < SortedSet < T > >用于创建 SortedSet 集合的比较器

示例

以下示例创建了一个 比较器(来自 SortedSet < double >),并用其创建一个存储两个 double 的 SortedSet 的 HashSet:

IEnumerable < double > ZHSs = [ 3 , 1 , 0 , -3 , 3 , 7 ];
IEnumerable < double > SJDs = [ 6.5 , 21.3 , -10 , -30.6 , 13.8 , 17.6 , 13.8 ];
SortedSet < double > ZHSs排序 = [ .. ZHSs ];
SortedSet < double > SJDs排序 = [ .. SJDs ];
IEqualityComparer < SortedSet < double > > bjq = SortedSet < double > . CreateSetComparer ( );
Console . WriteLine ( bjq . ToString ( ) );

HashSet < SortedSet < double > > JH = new ( bjq )
    {
    ZHSs排序,
    SJDs排序
    };
foreach ( var z in JH )
    {
    foreach ( var x in z )
        { Console . Write ( $"{x}\t" ); }
    Console . WriteLine ( );
    }

备注

IEqualityComparer 对象仅在一个级别检查相等性;但是,您可以在其他级别将比较器链接在一起,以执行更深入的相等性测试。

调用此方法是一个 O(1)操作。

成员相等比较器 和当前的 SortedSet < T > 必须具有相同的相等性定义;其为 null 则与不带参数的 CreateSetComparer 一个效果。

你可以在 SortedSet < T > . SortedSet < T > ( IEnumerable < T > , IComparer < T > ) 构造函数中使用此方法返回的比较器来创建各个集合的哈希表。

ExceptWith

从当前的 SortedSet < T > 对象中移除所有存在于指定集或集合中的元素(差集)。
public void ExceptWith ( System . Collections . Generic . IEnumerable < T > 另一个 );

参数

参数类型注解
另一个IEnumerable < T >欲在 SortedSet 中移除的项的集或集合

实现

ExceptWith ( IEnumerable < T > )

异常

异常注解
ArgumentNullException减集 为 null

示例

IEnumerable < double > ZHSs = [ 3 , 1 , 0 , -3 , 3 , 7 ];
IEnumerable < double > SJDs = [ 6.5 , 21.3 , -10 , -30.6 , 13.8 , 17.6 , 13.8 , 1 , 3 , 3 ];
SortedSet < double > ZHSs排序 = [ .. ZHSs ];
SortedSet < double > SJDs排序 = [ .. SJDs ];

ZHSs排序 . ExceptWith ( SJDs排序 );
foreach ( var z in ZHSs排序 )
    { Console . WriteLine ( z ); }

备注

此方法会移除当前 SortedSet < T > 中同时存在于 另一个 中的任何元素。另一个(如果是集)中的重复值会被忽略。

该方法等同于数学上的 A - B。

此方法是一个 O(n × log ( m ))操作,其中 m 为 SortedSet . Count,n 为 另一个 . Count。

GetViewBetween

返回 SortedSet < T > 中子集的视图。
public virtual System . Collections . Generic . SortedSet < T > GetViewBetween ( T? 低值 , T? 高值 );

参数

参数类型注解
低值T视图中所需的最低值
高值T视图中所需的最高值

返回值

类型注解
SortedSet < T >仅包含指定范围内值的子集视图

异常

异常注解
ArgumentException低值大于高值(依据比较器)
ArgumentOutOfRangeException视图上的尝试操作超出了 低值 和 高值 指定的范围

示例

以下示例描述了一个 Double SortedSet,并选择其中 0 到 7 范围内生成新的视图,且尝试引发 ArgumentOutOfRangeException:

IEnumerable < double > SJDs = [ 6.5 , 21.3 , -10 , -30.6 , 13.8 , 17.6 , 13.8 , 1 , 3 , 3 ];
SortedSet < double > SJDs排序 = [ .. SJDs ];

SortedSet < double > SJDs07 = SJDs排序 . GetViewBetween ( 0 , 7 ); // 生成以 SJDs排序 为基础的,包含其中 0 到 7 范围内的数值的视图
foreach ( var z in SJDs07 )
    { Console . WriteLine ( z ); }
try
    {
    SJDs07 . Add ( 8 ); // SJDs07 限制其值包括 0 到 7 范围内的 Double,所以向其添加 8 异常
    }
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); } // ArgumentOutOfRangeException

备注

此方法返回由比较器定义的、落在 低值 和 高值 之间的元素范围的视图。此方法不会从 SortedSet < T > 中复制元素,而是提供对基于 SortedSet < T > 本身的窗口。您可以在视图和基础 SortedSet < T > 中进行更改。例如例程中可以向视图 SJDs07 添加 5.5,SJDs排序 也添加了 5.5;也可以向 SJDs排序 添加 5.5,SJDs07 也添加了 5.5;但 SJDs07 的任意操作都被限制只能在 0 到 7 之间。

低值 和 高值 都可以是 null。低值 为 null,视图中包含所有小于 高值 的元素;高值 为 null,视图中包含所有大于 低值 的元素;均为 null,视图中包含所有 SortedSet 的元素。

IntersectWith

修改当前的 SortedSet < T > 对象,使其仅包含也存在于指定集或集合中的元素。
public virtual void IntersectWith ( System . Collections . Generic . IEnumerable < T > 另一个 );

参数

参数类型注解
另一个IEnumerable < T >欲与当前 SortedSet 实例比较的集或集合

实现

IntersectWith ( IEnumerable < T > )

异常

异常注解
ArgumentNullException另一个 为 null

示例

以下示例使用一个 集 修改 SortedSet 实例,获取其交集:

IEnumerable < double > SJDs = [ 6.5 , 21.3 , -10 , -30.6 , 13.8 , 17.6 , 13.8 , 1 , 3 , 3 ];
SortedSet < double > SJDs排序 = [ .. SJDs ];
IEnumerable < double > SJDs1 = [ 6.5 , 21.3 , 13 , 15 ];

SJDs排序 . IntersectWith ( SJDs1 );
foreach ( var z in SJDs排序 )
    { Console . Write ( $"{z}\t" ); }

备注

此方法忽略 另一个(若是集)中的任何重复元素。

执行 IntersectWith 方法后的 SortedSet 对象仅包含原 SortedSet 实例与 另一个 共同拥有的元素。等同于数学概念中的 A ∩ B。此时的 A 可能没有元素,因为 A ∩ B = ∅(没有共同元素)。

如果 交集 参数所表示的集合是与当前 SortedSet < T > 对象具有相同相等比较器的 SortedSet < T > 集合,则此方法是一个 O(n) 操作。否则,此方法是一个 O(n + m)操作,其中 n 为原 SortedSet . Count,m 为 交集 . Count。

IsProperSubsetOf、IsProperSupersetOf、IsSubsetOf 和 IsSupersetOf

描述某个集或集合是否是当前实例的真子集、真超集、子集和超集。

public bool IsProperSubsetOf ( System . Collections . Generic . IEnumerable < T > 真子集 );
public bool IsProperSupersetOf ( System . Collections . Generic . IEnumerable < T > 真超集 );
public bool IsSubsetOf ( System . Collections . Generic . IEnumerable < T > 子集 );
public bool IsSupersetOf ( System . Collections . Generic . IEnumerable < T > 超集 );

参数

参数类型注解
真子集
真超集
子集
超集
IEnumerable < T >欲与当前 SortedSet 实例比较的集或集合

返回值

类型注解
bool若参数指定的集或集合是当前实例的真子集、真超集、子集或超集,返回 true;否则返回 false

实现

IsProperSubsetOf ( IEnumerable < T > )
IsProperSupersetOf ( IEnumerable < T > )
IsSubsetOf ( IEnumerable < T > )
IsSupersetOf ( IEnumerable < T > )

异常

异常注解
ArgumentNullException参数 是 null

备注

若 SortedSet A = [ 1 , 2 , 3 , 4 , 5 ],B = [ 1 , 2 ],则
A 是 B 的真超集,记作 A ⊃ B;B 是 A 的真子集,记作 B ⊂ A(同时也分别是超集(⊇)和子集(⊆))。

超集即包含该 SortedSet 实例的所有元素的集合,真超集则还包含其他元素;子集即包含该 SortedSet 实例的全部或部分元素的集合,真子集仅包含部分元素。

空的 SortedSet 是任意集或集合的子集,是任意有元素的集或集合的真子集;任意集或集合是空的 SortedSet 的超集,有元素的集或集合是空的 SortedSet 的真超集。

如下表,这些方法将始终返回 false。

方法实例 . Count 与 参数 . Count
IsProperSubsetOf
IsSubsetOf
IsProperSupersetOf
IsSupersetOf

如果由 参数 表示的集或集合是与当前 SortedSet < T > 对象具有相同相等比较器的 SortedSet < T > 集合,则此方法是一个 O(n)操作。否则,此方法是一个 O(n + m)操作,其中 n 是 SortedSet . Count,m 是 参数 . Count。

Overlaps

确定当前的 SortedSet < T > 对象和指定的集或集合是否包含共同元素。
public bool Overlaps ( System . Collections . Generic . IEnumerable < T > 另一个 );

参数

参数类型注解
另一个IEnumerable < T >欲与当前 SortedSet 比较的集或集合

返回值

类型注解
bool如果 SortedSet 实例与 另一个 具有至少一个公共元素,则为 true;否则为 false

实现

Overlaps ( IEnumerable < T > )

异常

异常注解
ArgumentNullException另一个 为 null

备注

另一个(若是集)中的任何重复元素将被忽略。

该方法数学含义可表示为 A ∩ B ≠ ∅。即两集合或集有交集(有公共元素)。

此方法是一个 O(n × log ( m ))操作,其中 m 为 SortedSet . Count,n 为 另一个 . Count。最简单的情况是 SortedSet 实例或/和 另一个 是空集,O(1)操作,直接返回 false;否则,n 可能是大于等于 1 并小于等于 另一个 . Count 的任意值,直到找到共有元素为止,最坏的情况是检索到 另一个 的最后一个元素。

RemoveWhere

从 SortedSet < T > 中移除所有与指定谓词定义的条件相匹配的元素。
public int RemoveWhere ( Predicate < T > 匹配 );

参数

参数类型注解
匹配Predicate < T >定义要移除元素的条件的委托

返回值

类型注解
Int32从 SortedSet < T > 集合中移除的元素数量

异常

异常注解
ArgumentNullException匹配 为 null

示例

以下示例创建一个 20 个元素的 int SortedSet,并从中移除 2 的倍数和 3 的倍数,但不移除即是 2 的倍数又是 3 的倍数(即 6 的倍数):

SortedSet < int > ZHSs排序 = [ ];
for ( int z = 0 ; z <= 19 ; z++ )
    ZHSs排序 . Add ( z );
int zhs项目 = ZHSs排序 . RemoveWhere ( FF2Or3B );
Console . WriteLine ( $"共移除了 {zhs项目} 项。" );
foreach ( var z in ZHSs排序 ) Console . WriteLine ( z );

static bool FF2Or3B ( int 整数 )
    {
    bool ber2he3B = 整数 % ( 2 * 3 ) == 0;
    bool ber2huo3B = 整数 % 2 == 0 || 整数 % 3 == 0;
    // 仅当 整数 是 2 的倍数且不是 3 的倍数;或者是 3 的倍数且不是 2 的倍数,返回 true
    return ber2huo3B && !ber2he3B;
    }

备注

匹配 不得修改 SortedSet < T >。这样做可能会导致意外结果。

调用此方法是一个 O(n)操作,其中 n 为 SortedSet . Count。

Reverse

返回一个 IEnumerable < T >,它按相反顺序循环访问 SortedSet < T >。
public System . Collections . Generic . IEnumerable < T > Reverse ( );

返回值

类型注解
IEnumerable < T >一个枚举数,用于按相反顺序迭代 SortedSet < T >

示例

以下示例创建了一个 10 个元素的 SortedSet,并将其反转:

SortedSet < int > ZHSs排序 = [ ];
for ( int z = 0 ; z <= 9 ; z++ )
    ZHSs排序 . Add ( z );

Console . WriteLine ( "倒序前:" );
foreach ( var z in ZHSs排序 )
    { Console . Write ( $"{z}\t" ); }
Console . WriteLine ( );

IEnumerable < int > ZHSs倒序 = ZHSs排序 . Reverse ( );
Console . WriteLine ( "倒序后:" );
foreach ( var z in ZHSs倒序 )
    { Console . Write ( $"{z}\t" ); }
Console . WriteLine ( );

// 以下代码依然使用上述代码,但在输出 ZHSs倒序 之前,向 ZHSs排序 添加了一个元素 20
Console . WriteLine ( "倒序前:" );
foreach ( var z in ZHSs排序 )
    { Console . Write ( $"{z}\t" ); }
Console . WriteLine ( );

ZHSs排序 . Add ( 20 );
Console . WriteLine ( "倒序后:" );
foreach ( var z in ZHSs倒序 )
    { Console . Write ( $"{z}\t" ); }
Console . WriteLine ( );

备注

返回值 是 SortedSet 实例的一个镜本(不是副本,不可修改),对 SortedSet 实例的修改(离开镜子,延迟读取)会在执行 Reverse 时立刻反映在返回值中(再次照镜子)。

SetEquals

确定当前的 SortedSet < T > 对象和指定的集或集合是否包含相同的元素。
public bool SetEquals ( System . Collections . Generic . IEnumerable < T > 另一个 );

参数

参数类型注解
另一个IEnumerable < T >欲与当前 SortedSet 实例比较的集或集合

返回值

类型注解
bool当前 SortedSet 实例与 另一个 相等,则为 true,否则为 false

实现

SetEquals ( IENumable < T > )

异常

异常注解
ArgumentNullException另一个 是 null

示例

以下示例创建三个 SortedSet 或实现 IEnumerable 接口的对象,与 SortedSet 实例进行比较:

IEnumerable < int > ZHSs整数 = [ 3 , 1 , 2 ];
SortedSet < int > ZHSs排序 = [ .. ZHSs整数 ];
IEnumerable < int > BJMB2 = [ 3 , 1 , 1 , 2 ];
IEnumerable < int > BJMB3 = BJMB2 . Append ( 4 );

object [ ] BJMB =
    [
    new SortedSet < int > ( [ .. ZHSs整数 ] ),
    BJMB2,
    BJMB3,
    ];

foreach ( var bj in BJMB )
    Console . WriteLine ( $"ZHSs排序 . SetEquals ( {string . Join ( "," , ( IEnumerable < int > ) bj )} ) = {ZHSs排序 . SetEquals ( ( IEnumerable < int > ) bj )}" );

备注

此方法忽略 另一个 中元素的顺序和任何重复元素。

如果由 另一个 表示的集合是与当前 SortedSet < T > 对象具有相同相等比较器的 SortedSet < T > 集合,则此方法是一个 O(log ( n ))操作。否则,此方法是一个O(n + m)操作,其中 n 是 另一个 . Count,m 是 SortedSet . Count。

SymmetricExceptWith

修改当前的 SortedSet < T > 对象,使其仅包含存在于当前对象中或指定集合中,但不同时存在于两者中的元素(即对称差集)。
public void SymmetricExceptWith ( System . Collections . Generic . IEnumerable < T > 另一个 );

参数

参数类型注解
另一个IEnumerable < T >欲与当前 SortedSet 实例比较的集或集合

实现

SymmetricExceptWith ( IEnumerable < T > )

异常

异常注解
ArgumentNullException另一个 是 null

备注

另一个 中的任何重复元素都会被忽略。

A . SymmetricExceptWith ( B ) 之后,A 将保留属于 A 但不属于 B 的元素,移除既属于 A 且属于 B 的元素,添加属于 B 但不属于 A 的元素。即数学上的 A △ B,或 (A - B) ∪ (B - A)。

如果 另一个 参数是与当前 SortedSet < T > 对象具有相同相等比较器的 SortedSet < T > 集合,则此方法是一个 O(n × log ( m ))操作。否则,此方法是一个 O(n × log ( m )) + O(n × log ( n ))操作,其中 n 是 另一个 . Count,m 是 SortedSet . Count。

TryGetValue

在集合中搜索给定值,如果找到相等的值,则输出该值。
public bool TryGetValue ( T 搜索值 , out T 输出值 );

参数

参数类型注解
搜索值T欲搜索的值
输出值T当方法返回 true,该值即为 搜索值;否则,该值是 T 类型的默认值

返回值

类型注解
bool若搜索到 搜索值,返回 true;否则返回 false

备注

当您的 SortedSet 是引用类型(string、class 等),想要重复使用以前存储的引用而不是新构建的引用(以便可以发生更多引用共享)或查找比当前值具有更完整数据的值时,这可能很有用,尽管它们的比较器函数表明它们是相等的。但对于值类型(int、struct 等),输出值 是 搜索到的值 的副本(或者默认值),只能表示该值是否存在于 SortedSet 中,倒不如使用 Contains 方法。

当 搜索值 即为 T 类型的默认值,例如在 int SortedSet 中搜索 0,返回值为 true,输出值是 0,表示搜索到 0;否则,没有搜索到该值,但输出值依然是 0。无论搜索什么值,不要以 输出值 的内容判断该值是否存在,必须由该方法的返回值确定。

UnionWith

修改当前的 SortedSet < T > 对象,使其包含当前对象和指定集或集合中存在的所有元素。
public void UnionWith ( System . Collections . Generic . IEnumerable < T > 另一个);

参数

参数类型注解
另一个IEnumerable < T >欲与当前 SortedSet 实例合并的集或集合

实现

UnionWith ( IEnumerable < T > )

异常

异常注解
ArgumentNullException另一个 为 null

备注

另一个(如果是集)中的任何重复元素都会被忽略。该方法即数学中的并集(A ∪ B)。

昨天喝了 2026 农历年第一杯咖啡,嫖到免单卡,3 块钱,拿到手初喝一口觉得有点水,我打趣说是不是老板看到我 3 块钱的单就给我偷工减料了。

事实证明我错了,起初一小时似乎还毫无感觉,紧接着就是熟悉的心跳加速,不止于此,这次还着实触发了焦虑开关。我不知道该如何向其他人准确描述这种体验,最明显的是两种感觉。一是觉得左右脑互搏,念头会接二连三涌出来通常是不好的念头,这也可能跟 ADHD 有关。二是整个人处于受惊状态,别人大声说话会下意识很害怕,像应激的小猫一样。

早上十点多点的咖啡,上述状态就这么维持到了睡前。我也知道,如果我整天处于这种神经燃烧的状态晚上必失眠了,即使我前一晚也没睡好,这也是我早上点咖啡的原因。爸妈临睡觉还在那吵架,身边的事实真的让我对人类对自己感情驾驭能力的绝望,不只是小孩,成人无法控制愤怒也是绝大多数。当然我肯定不是像个圣人一样指责别人控制不了愤怒,因为我很清楚我自己也控制不了。

有点出乎意料。晚上我倒是好像挺快睡着了,可能半个小时?然而半夜才是主战场,最近都是。近来我的非焦虑、非兴奋型失眠的情况下,我都是入睡容易,但是半夜醒了就很难再睡回去,经常是辗转到看到天亮了,才能再睡过去。而这篇记录,就写在 2026-02-22 06:21 ,因为这次尤其离谱,我感觉翻来覆去有两个小时了,天还没亮,大概是四五点就醒了,我觉得很无奈,很浪费时间,就起来码点字了。

再讲讲我的失眠史吧,失眠的时候我经常会问自己,到底是从什么时候开始的?回忆起来,我好像还打小就这样,不太爱睡觉。

小学的时候,九点多就上床睡觉,实际上是在玩毛绒玩具,跑脑内剧本,估计没个十点多肯定是没睡着。早上起来也是早,包括周末,我现在还记得,以前周末七点起床,打开电视没东西看,出去逛街书店便利店全都没开门,把我无聊死了。

遇到春游,小学初中都一样,前一晚必失眠,最初可能是因为春游兴奋,毕竟一年一度,可以去玩,还能吃好多零食。但是后面已经不能确定是因为兴奋还是纯粹的自证预言了。这种就是我上面说的兴奋型失眠,一直都很常见。例如一年前去马尔代夫,前一晚没睡好,去到那边中转酒店也是听了一整夜的车声。

又例如高考第一天前一晚,也是史诗级失眠。我到现在都无法想象,那一晚,我猜也就睡了顶多四个小时吧。最初在自己床上翻来覆去,然后不知道咋的就去跟我爸一起睡,嗯,也不是单纯是睡,睡不着就聊两句。当时就是整个脑子都很兴奋,感觉直接进考试状态了,完全止不住。真的很难想象我能以四个小时睡眠把第一天高考考完还没想象中拉跨的,还好第二天晚上不知道因为困了还是真正进入考试区间了,印象中没有失眠。

至于焦虑型失眠,原理也类似,忘了以前哪本书说,演讲前你要把心跳加速从焦虑理解成兴奋,这样会发挥得更好。确实,这两者表现确实很像,这些年被社会毒打之后造成的焦虑型失眠跟兴奋型失眠也是基本一样的感觉。也就是毫无睡意,左右脑互搏,有时候还会有一些很具体的意象冒出来,还一直重复。焦虑型还会冒冷汗,上次应该是玩合约的时候,傻傻的上来就 100 倍杠杆,睡前开始亏钱,结果就完全睡不着了,最后还是翻起来平仓了,亏了一百多刀,是的,真的很少,但还是让我焦虑症了……

最后是咖啡因失眠。咖啡这个东西,真是既爱又恨。这又是我记得很清楚的一件事,跟女朋友聊得很晚,没有睡好。然后第二天快下班的时候,也就是五六点,老板带我去见乙方,在猫屎咖啡点了一杯冰拿铁,就是这杯冰拿铁触发了我人生第一次咖啡因崩溃。我是真的整个人都崩溃了,晕得崩溃,那天晚上吃的什么高级西餐都在痛苦中进行,毫无快感。也因为那天下午喝的咖啡,理所当然的当晚也几乎通宵。从这事我才知道,原来我不能喝咖啡啊?那我之前喝的到底是啥?还是说我之前没事的,打工之后变脆皮了?但是回忆起来吧,可能以前高中好几次莫名奇妙的失眠都是因为晚上喝了茶,但是那时候我根本没有意识到咖啡因的威力。

写到这里 07:00 了,天已经亮了。也就是可能从五点醒到现在了,又是离谱的一天,还好不用上班啊……

总之吧,感觉我一生都要跟失眠战斗了,虽然我这也不算严重的了,但是都已经开始考虑在家里备点苯海拉明了,或者再找找有什么副作用更小的药或者补剂。不知道有没有病友,大家交流一下吧😂

Windows Server 2022 OVF (2026 年 2 月更新) - VMware 虚拟机模板

Windows Server 2022 Datacenter x64 OVF, updated Feb 2026 (sysin)

请访问原文链接:https://sysin.org/blog/windows-server-2022-ovf/ 查看最新版。原创作品,转载请保留出处。

作者主页:sysin.org


现在都是自动 sysprep 的版本,版本同步更新。

Windows Server 2022 Datacenter x64 Chinese Simplified / English

Version 21H2, updated Feb 2026

Microsoft Windows Server 2022

Windows Server 2022 OVF

部署截图及说明

计算资源选项

CPU 和内存配置选项,可以部署完毕后任意编辑

用户账号和网络配置

注:本例截图来自 Fusion,在 vSphere 和 Workstation 中展现样式略有差异,内容相同。

请注意:

1.1 此处密码必须符合复杂性要求(系统默认值)

密码必须符合下列最低要求:

  • 不能包含用户的帐户名,不能包含用户姓名中超过两个连续字符的部分
  • 至少有六个字符长
  • 包含以下四类字符中的三类字符:

    • 英文大写字母 (A 到 Z)
    • 英文小写字母 (a 到 z)
    • 10 个基本数字 (0 到 9)
    • 非字母字符 (例如 !、$、#、%)
  • 在更改或创建密码时执行复杂性要求

1.2 删除内置的 sysadmin 账号(此项设置已经不存在,无任何其他非默认账号)

2.2 子网掩码前缀使用 CIDR 表示法,例如掩码 255.255.255.0 填写 24

2.5 Hostname:计算机名称

因部分读者不知道计算机名称怎么填写而报错,这里增加一个计算机名称的描述。

计算机名称包括 NetBIOS 名称和 DNS 名称,MS 官方规则稍显复杂,这里简单概括或者建议使用如下规则:

  • 长度 1-15 个字符
  • 字符使用三种类型或其组合:字母字符 (A-Z,不区分大小写) 、数字字符 (0-9) 、减号或称连字符 (-)
  • 推荐 3 种示例:全部字母,字母和数字组合,字母-数字或者数字-字母(中间允许多个-)
  • 不要全部用数字(NetBIOS 名称可以支持,但 DNS 名称不允许)

如果使用 DHCP 配置,计算机名称将自动随机生成格式如 WIN-xxxxxxxxxxx。

OVF 特性

1. OVF 版本

  1. 默认 VM 硬件版本 11(GuestOS ID 最低要求 10,可升级至最新版),兼容 ESXi 6.0、Fusion 7、Workstation 11 及以上;
  2. 启用 CPU、内存热插拔 (sysin)
  3. VM-Tools 版本:13.0.10.0(当前)✝️➕ 版本更新

2. 系统配置

  1. 时间和货币格式:Chinese (Simplified, China),默认键盘和输入方法:简体中文 - 美式键盘(US)
  2. 系统版本:Windows Server 2022 Datacenter, with DesktopExperience
  3. 分区:System Reserve(100M),Recovery Partition(550M)移到 C 盘之前,C 盘 40G 整数分区(可自由调整),2022年6月及以后的版本已删除恢复分区
  4. 启用远程桌面 (sysin)
  5. 启用 ICMPv4 防火墙规则
  6. 早期版本添加了名为 sysadmin 的管理员账号,现在已经取消该项配置
  7. 添加了 “Command Prompt” 和 “PowerShell” 右键快捷命令菜单(增加图标)
  8. 修改 Windows Update 为手动(可通过 sconfig 恢复,禁用或者启用服务无效)
  9. 添加了 “FileHash” 右键快捷命令菜单(内置 PowerShell 命令实现)
  10. 关闭 Telemetry(遥测)
  11. 设置 Administrator 账号密码永不过期(默认 sysprep 后密码会过期)✝️➕ 新增
  12. 禁用 “Azure Arc Setup” 自动运行 ✝️➕ 新增
  13. 已禁用 Windows Update,通过 Windows Update Blocker ✝️➕ 新增

3. 中英文界面语言切换

提示:该项功能已弃用

英文版添加了简体中文界面语言支持,切换方法如下:

Settings > Time & Language > Language, Windows Display Languages 下拉勾选 ”Chinese (Simplified, China)”

注销登录或者重启生效。

另外,如果再次运行 sysprep,欢迎画面也会提示选择语言(“English” 或者 “中文(简体)”)。

重要更新

2023 年 6 月更新开始,将提供英文版和简体中文版两个独立版本,根据近期的用户反馈,发现了官方产品存在重大 bug:系统文件每月都有一定的更新,但是语言包从未更新(或未同步更新),无论是在线更新语言包或者离线从 iso 安装。这将导致切换到简体中文界面语言后,系统及其自带的应用程序(部分)或报错或功能异常。

4. OEM BIOS 支持

支持 Dell OEM 2.6 及以上版本的 BIOS。推荐使用本站 VMware 定制版启用完整功能,参看下述 “适用的 VMware 软件下载”。

💡 特别提示:这里的 OEM BIOS 是软件技术,并非硬件的 BIOS,可适用于任何品牌的计算机以及任意兼容机。标题中的 Dell 只是采用了最流行的 Dell 产品技术方案。

💡 特别提示:这里的 OEM BIOS 是软件技术,并非硬件的 BIOS,可适用于任何品牌的计算机以及任意兼容机。标题中的 Dell 只是采用了最流行的 Dell 产品技术方案。

5. 系统组件

  1. 添加组件:Telnet Client、SNMP-Service、Windows Backup
  2. 添加组件:.NETFX 3.5 (启用此组件需要系统 ISO 映像,这里预先配置)

6. 远程桌面性能优化

  1. 禁用 Logon Backgroud

    echo 个性化设置:禁用登录背景 Logon Image
    reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\System" /v DisableLogonBackgroundImage /t REG_DWORD /d 1 /f
  2. 更换 Lock Screen 为默认蓝色

    echo 个性化设置:禁用设置中 Lock Screen 功能
    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Personalization" /v NoLockScreen /t REG_DWORD /d 1 /f
  3. 替换 Desktop Backgroud 为灰色

7. 应用软件

  1. AutoRuns 14.0、7-Zip 26.00、Unlocker 1.9.2(全部为免费软件) ✝️➕ 版本更新
  2. 浏览器:Firefox 140,通过策略禁用自动更新,默认为所有用户添加开始菜单和桌面快捷方式 ✝️➕ 版本更新
  3. Defender Control,可以快速禁用 Windows Defender(快捷方式在开始菜单)✝️➕ 新增
  4. Windows Update Blocker,可以快速禁用系统自动更新(快捷方式在开始菜单)✝️➕ 新增
说明:以上软件版本描述的是更新版本,旧版 OVF 包含的版本可能略低。

8. 个性化配置

  1. 用户配置(此项配置 sysprep 后无效)

    echo 个性化配置:标题栏显示颜色(仅针对当前用户有效,针对计算机设置无效)(此项可通过 Load Hive 预先配置)
    reg add "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\DWM" /v ColorPrevalence /t REG_DWORD /d 1 /f
  2. 几个关于隐私和使用记录的配置,通过 HKEY_LOCAL_MACHINE 预先配置

    echo 个性化配置:Turn off to Show recently opened items in Jump Lists on Start or the taskbar
    reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_TrackDocs /t REG_DWORD /d 0 /f
    
    echo Folder Options:Open File Explorer to: This PC
    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v LaunchTo /t REG_DWORD /d 1 /f
    
    echo Folder Options:Turn off to Show recently used files in Quick access
    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" /v ShowRecent /t REG_DWORD /d 0 /f
    
    echo Folder Options:Turn off to Show frequently used folders in Quick access
    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" /v ShowFrequent /t REG_DWORD /d 0 /f

9. 关于 GuestOS ID

GuestOS ID 默认为 Windows Server 2016 or later,因为需要兼容低版本的 VM Hardware,否则将无法识别 GuestOS,对于支持高版本 VM Hardware 的环境,可以在导入后手动选择。当然也可以忽略,因为目前为止 Windows Server 2016、2019、2022 实际都是 windows9Server64Guest(Windows 10 Server)。

10. sysprep

✝️➕ 新特性

本次更新开始将自动运行 sysprep,生成新的 sid。如果手动配置计算机名称和 IP 地址,系统初始化将重启两次。如果使用 DHCP 配置,计算机名称将自动随机生成格式如 WIN-xxxxxxxxxxx。

适用的 VMware 软件下载

建议在以下版本的 VMware 软件中运行(Linux OVF 无需本站定制版可以正常运行,macOS 虚拟化如果不是 Mac 必须使用定制版才能运行,Windows OVF 需要定制版才能启用完整功能):

OVF 版本兼容性和部署方式

默认使用 VM 硬件版本 11(GuestOS ID 最低要求 10,可升级至最新版),兼容 ESXi 6.0、Fusion 7、Workstation 11、Player 7 及以上版本。

支持通过以下客户端部署:

  • VMware Fusion for Mac:12、13 及更新版本(推荐版本 13 及以上)
  • VMware Workstation for Windows & Linux:16、17 及更新版本(推荐版本 17 及以上)
  • VMware vSphere(vSphere Client):7.0、8.0、9.0 及更新版本(推荐 7.0U3 及以上)
  • ESXi Host Client:内置于 ESXi 7.0U3、8.0、9.0 及更新版本(推荐版本 2.10.1 及以上)
部分已经废弃的客户端如 vSphere Web Cleint(Flash),以及上述客户端旧版不建议使用。

客户端系统和软件要求:

下载地址

保留最近三个版本。

Windows Server 2022 LTSC Datacenter x64 Chinese Simplified / English (updated Feb 2026),现在自动运行 sysprep


原版下载:Windows Server 2022 中文版、英文版下载 (2026 年 2 月更新)

更多:VMware 产品下载汇总

大家新年快乐!

我想入手一台平板,用来满足以下需求:

  1. 阅读

  2. 办公

  3. 科学上网(很重要)

  4. 轻量游戏

目前我在看两个方向:

  • vivo 平板的一个优势是它有一套比较强大的办公套件,适合处理文档、笔记、绘图等日常办公需求。

  • 一加平板的一个优势是据说支持 Bootloader 解锁(我查过资料,好像 vivo 平板不支持,不知道有没有理解错误,欢迎指正)。

我的预算大概是在转转上买一台 2000 元左右的二手平板。

基于上述需求和考虑,大家觉得我应该选哪个品牌?

谢谢!

看了一下现在的中转站基本都是按 token 卖的,对于重度 openclaw 选手来说,有点贵了。这几天我捣鼓了个按天计费的中转,一天只要几块钱。也有一些其他模型例如 glm5 ,qwen 3.5 plus ,k2.5 等。

[闲鱼] https://m.tb.cn/h.7BL0MIt?tk=5tRJULKTpU0 HU926 「我在闲鱼发布了 [ Codex API 5.3 低延迟直连] 」
点击链接直接打开

有办法降低这个 token 消耗吗,我用的 kimi2.5 ,给了两个网站打开然后读取信息的任务,直接干了 1 块钱。其中卡了一下(是我的 tg 卡了可能),我多发了一次指令,结果,2 块钱没了。后面我试了就算是一句 hello ,也要几毛钱。😂,然后突然就被限流了。



不过用起来还挺有意思的,让他帮我看看 pm2 任务状态啥的也很方便,就是消耗太快了。😶。

学习代码细节对我来说真的很慢很痛苦(正反馈太少),个人更喜欢眼高手低的先学架构设计层面的,以前没有 ai 的情况,这种模式只适合像老印一样打打嘴炮,一遇到"talk is cheap, show me the code"就 gg ;现在 AI 很好的补齐了我手低的缺点,简直是舒服。

大家好,我是良许。

最近在做一个智能家居项目的时候,客户提出了一个让我头疼的问题:"你们的设备安全吗?会不会被黑客攻击?"

这个问题让我意识到,在物联网时代,安全问题已经不再是可有可无的附加功能,而是必须从设计之初就要考虑的核心要素。

今天就和大家聊聊物联网安全和认证技术这个话题。

1. 物联网安全面临的挑战

1.1 物联网设备的脆弱性

物联网设备和传统的 PC 或服务器不同,它们往往资源受限,计算能力弱,存储空间小。

我之前做过一个项目,使用的是 STM32F103 系列单片机,Flash 只有 64KB,RAM 只有 20KB。

在这样的硬件条件下,想要实现复杂的加密算法和安全机制,确实是个不小的挑战。

更要命的是,很多物联网设备部署在无人值守的环境中,比如智能电表、环境监测传感器等。

这些设备一旦被部署,可能几年都不会有人去维护,这就给攻击者提供了充足的时间去研究和攻击。

我见过一个案例,某个智能门锁因为固件更新机制不完善,被黑客利用漏洞远程开锁,造成了严重的安全事故。

1.2 通信链路的安全风险

物联网设备通常通过无线方式通信,比如 WiFi、蓝牙、LoRa、NB-IoT 等。

这些无线通信天然就存在被窃听、被篡改的风险。

我在做汽车电子项目时,就遇到过 CAN 总线被恶意注入数据包的情况,虽然 CAN 总线是有线通信,但如果没有适当的安全措施,同样容易受到攻击。

无线通信的另一个问题是重放攻击。

攻击者可以截获合法的通信数据包,然后在稍后的时间重新发送,从而欺骗系统。

比如,攻击者截获了开门的指令,然后在主人离开后重放这个指令,就能非法进入房间。

1.3 数据隐私保护

物联网设备收集的数据往往涉及用户隐私。

智能手环记录你的运动轨迹和健康数据,智能音箱可能录下你的对话,智能摄像头更是直接拍摄你的生活场景。

如果这些数据没有得到妥善保护,后果不堪设想。

我曾经参与过一个智能医疗设备的项目,设备需要采集患者的生理数据并上传到云端。

在设计阶段,我们就必须考虑如何对这些敏感数据进行加密存储和传输,确保即使数据被截获,攻击者也无法解读其内容。

2. 物联网认证技术

2.1 设备身份认证

在物联网系统中,首先要解决的问题是"你是谁"。

设备身份认证就是确保连接到网络的设备是合法的、可信的。

2.1.1 基于密钥的认证

最常见的认证方式是基于预共享密钥(PSK)。

在设备出厂时,就为每个设备分配一个唯一的密钥,这个密钥同时存储在设备和服务器端。

当设备连接到网络时,通过密钥进行身份验证。

下面是一个简单的基于 HMAC-SHA256 的认证示例代码:

#include "stm32f4xx_hal.h"
#include "mbedtls/md.h"
#include <string.h>
​
// 设备唯一密钥(实际应用中应该安全存储)
const uint8_t device_key[32] = {
    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
​
// 生成认证令牌
int generate_auth_token(const char* device_id, uint32_t timestamp, 
                        uint8_t* token, size_t token_len)
{
    mbedtls_md_context_t ctx;
    const mbedtls_md_info_t* md_info;
    uint8_t message[128];
    int ret;
    
    // 构造待签名的消息:设备ID + 时间戳
    snprintf((char*)message, sizeof(message), "%s:%lu", device_id, timestamp);
    
    // 初始化HMAC-SHA256
    mbedtls_md_init(&ctx);
    md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    
    ret = mbedtls_md_setup(&ctx, md_info, 1); // 1表示启用HMAC
    if (ret != 0) {
        return -1;
    }
    
    // 设置密钥
    ret = mbedtls_md_hmac_starts(&ctx, device_key, sizeof(device_key));
    if (ret != 0) {
        mbedtls_md_free(&ctx);
        return -1;
    }
    
    // 计算HMAC
    ret = mbedtls_md_hmac_update(&ctx, message, strlen((char*)message));
    if (ret != 0) {
        mbedtls_md_free(&ctx);
        return -1;
    }
    
    ret = mbedtls_md_hmac_finish(&ctx, token);
    if (ret != 0) {
        mbedtls_md_free(&ctx);
        return -1;
    }
    
    mbedtls_md_free(&ctx);
    return 0;
}
​
// 验证认证令牌
int verify_auth_token(const char* device_id, uint32_t timestamp,
                      const uint8_t* received_token)
{
    uint8_t calculated_token[32];
    
    // 生成预期的令牌
    if (generate_auth_token(device_id, timestamp, calculated_token, 
                           sizeof(calculated_token)) != 0) {
        return -1;
    }
    
    // 比较令牌
    if (memcmp(calculated_token, received_token, 32) == 0) {
        return 0; // 验证成功
    }
    
    return -1; // 验证失败
}

这段代码展示了如何使用 HMAC-SHA256 算法生成和验证认证令牌。

设备使用自己的密钥和当前时间戳生成令牌,服务器端使用相同的算法验证令牌的有效性。

时间戳的加入可以防止重放攻击,因为旧的令牌会因为时间戳过期而失效。

2.1.2 基于证书的认证

对于安全要求更高的场景,可以使用基于 X.509 证书的认证机制。

每个设备都有一个由可信 CA 签发的数字证书,证书中包含设备的公钥和身份信息。

在认证过程中,设备出示自己的证书,服务器验证证书的有效性,并通过公钥加密的方式确认设备拥有对应的私钥。

我在做汽车电子项目时,就采用了这种方案。

车载 ECU 之间的通信使用 TLS 协议,每个 ECU 都有自己的证书。

这样即使 CAN 总线被物理接入,攻击者也无法伪造合法的 ECU,因为他没有对应的私钥。

2.2 用户身份认证

除了设备认证,用户身份认证同样重要。

用户通过手机 APP 或 Web 界面访问物联网设备时,需要证明自己的身份。

2.2.1 多因素认证

单纯的用户名密码认证已经不够安全了。

现在越来越多的物联网系统采用多因素认证(MFA),比如密码加短信验证码,或者密码加生物识别(指纹、人脸等)。

我在设计一个智能门锁系统时,就实现了三层认证:首先是手机 APP 的登录密码,然后是蓝牙配对验证,最后是门锁本身的指纹识别。

只有三层验证都通过,门锁才会打开。

这种多层防护机制大大提高了系统的安全性。

2.2.2 OAuth 2.0 授权

对于需要第三方服务集成的物联网系统,OAuth 2.0 是一个很好的选择。

用户可以授权第三方应用访问自己的物联网设备,而不需要把自己的账号密码告诉第三方。

比如,你可以授权 Google Assistant 控制你的智能灯泡,但 Google 只能获得有限的权限,不能访问你的其他设备或个人信息。

这种授权机制既方便了用户,又保护了隐私。

2.3 数据完整性验证

除了身份认证,我们还需要确保数据在传输过程中没有被篡改。

这就需要用到消息认证码(MAC)或数字签名技术。

下面是一个使用 CRC32 进行数据完整性校验的简单示例:

#include "stm32f4xx_hal.h"
​
// CRC32多项式(以太网标准)
#define CRC32_POLYNOMIAL 0xEDB88320
​
// 计算CRC32
uint32_t calculate_crc32(const uint8_t* data, size_t length)
{
    uint32_t crc = 0xFFFFFFFF;
    
    for (size_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 1) {
                crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
            } else {
                crc = crc >> 1;
            }
        }
    }
    
    return ~crc;
}
​
// 发送带CRC校验的数据包
typedef struct {
    uint8_t header;
    uint8_t device_id;
    uint16_t data_length;
    uint8_t data[256];
    uint32_t crc32;
} __attribute__((packed)) secure_packet_t;
​
int send_secure_packet(UART_HandleTypeDef* huart, uint8_t device_id,
                       const uint8_t* data, uint16_t length)
{
    secure_packet_t packet;
    
    // 填充数据包
    packet.header = 0xAA;
    packet.device_id = device_id;
    packet.data_length = length;
    memcpy(packet.data, data, length);
    
    // 计算CRC32(不包括CRC字段本身)
    packet.crc32 = calculate_crc32((uint8_t*)&packet, 
                                   sizeof(packet) - sizeof(uint32_t));
    
    // 发送数据包
    if (HAL_UART_Transmit(huart, (uint8_t*)&packet, 
                         sizeof(packet.header) + sizeof(packet.device_id) +
                         sizeof(packet.data_length) + length + sizeof(uint32_t),
                         1000) != HAL_OK) {
        return -1;
    }
    
    return 0;
}
​
// 接收并验证数据包
int receive_secure_packet(UART_HandleTypeDef* huart, secure_packet_t* packet)
{
    uint32_t calculated_crc;
    
    // 接收数据包头
    if (HAL_UART_Receive(huart, (uint8_t*)packet, 4, 1000) != HAL_OK) {
        return -1;
    }
    
    // 验证包头
    if (packet->header != 0xAA) {
        return -2;
    }
    
    // 接收数据和CRC
    if (HAL_UART_Receive(huart, packet->data, 
                        packet->data_length + sizeof(uint32_t), 
                        1000) != HAL_OK) {
        return -1;
    }
    
    // 计算并验证CRC
    calculated_crc = calculate_crc32((uint8_t*)packet,
                                     sizeof(packet->header) + 
                                     sizeof(packet->device_id) +
                                     sizeof(packet->data_length) + 
                                     packet->data_length);
    
    if (calculated_crc != packet->crc32) {
        return -3; // CRC校验失败
    }
    
    return 0; // 验证成功
}

这个例子展示了如何在数据传输中加入 CRC32 校验。

虽然 CRC 主要用于检测传输错误而不是防止恶意篡改,但它是数据完整性验证的基础。

对于更高的安全要求,应该使用 HMAC 或数字签名。

3. 数据加密技术

3.1 对称加密

对称加密算法使用相同的密钥进行加密和解密,速度快,适合资源受限的物联网设备。

常用的对称加密算法有 AES、DES、3DES 等,其中 AES 是目前最广泛使用的。

3.1.1 AES 加密实现

在 STM32 平台上,我们可以使用硬件加密模块或软件库来实现 AES 加密。

下面是使用 mbedTLS 库实现 AES-128-CBC 加密的示例:

#include "mbedtls/aes.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include <string.h>
​
// AES密钥(128位)
const uint8_t aes_key[16] = {
    0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
    0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};
​
// 加密函数
int aes_encrypt_data(const uint8_t* plaintext, size_t plaintext_len,
                     uint8_t* ciphertext, uint8_t* iv)
{
    mbedtls_aes_context aes;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    const char* personalization = "iot_device_aes";
    int ret;
    size_t padded_len;
    uint8_t padded_data[256];
    
    // 初始化随机数生成器
    mbedtls_entropy_init(&entropy);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                               (const uint8_t*)personalization,
                               strlen(personalization));
    if (ret != 0) {
        return -1;
    }
    
    // 生成随机IV
    ret = mbedtls_ctr_drbg_random(&ctr_drbg, iv, 16);
    if (ret != 0) {
        return -1;
    }
    
    // PKCS7填充
    padded_len = ((plaintext_len / 16) + 1) * 16;
    memcpy(padded_data, plaintext, plaintext_len);
    uint8_t padding_value = padded_len - plaintext_len;
    for (size_t i = plaintext_len; i < padded_len; i++) {
        padded_data[i] = padding_value;
    }
    
    // 初始化AES上下文
    mbedtls_aes_init(&aes);
    ret = mbedtls_aes_setkey_enc(&aes, aes_key, 128);
    if (ret != 0) {
        mbedtls_aes_free(&aes);
        return -1;
    }
    
    // 执行CBC模式加密
    ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, padded_len,
                               iv, padded_data, ciphertext);
    
    // 清理
    mbedtls_aes_free(&aes);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    
    return (ret == 0) ? padded_len : -1;
}
​
// 解密函数
int aes_decrypt_data(const uint8_t* ciphertext, size_t ciphertext_len,
                     uint8_t* plaintext, const uint8_t* iv)
{
    mbedtls_aes_context aes;
    uint8_t decrypted_data[256];
    int ret;
    uint8_t padding_value;
    size_t plaintext_len;
    
    // 初始化AES上下文
    mbedtls_aes_init(&aes);
    ret = mbedtls_aes_setkey_dec(&aes, aes_key, 128);
    if (ret != 0) {
        mbedtls_aes_free(&aes);
        return -1;
    }
    
    // 执行CBC模式解密
    uint8_t iv_copy[16];
    memcpy(iv_copy, iv, 16); // CBC模式会修改IV,所以要复制
    ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, ciphertext_len,
                               iv_copy, ciphertext, decrypted_data);
    
    mbedtls_aes_free(&aes);
    
    if (ret != 0) {
        return -1;
    }
    
    // 去除PKCS7填充
    padding_value = decrypted_data[ciphertext_len - 1];
    if (padding_value > 16 || padding_value == 0) {
        return -1; // 无效的填充
    }
    
    plaintext_len = ciphertext_len - padding_value;
    memcpy(plaintext, decrypted_data, plaintext_len);
    
    return plaintext_len;
}

这段代码实现了完整的 AES-128-CBC 加密和解密流程,包括随机 IV 生成、PKCS7 填充等细节。

在实际应用中,IV 必须是随机生成的,并且需要和密文一起传输给接收方。

3.2 非对称加密

非对称加密使用一对密钥:公钥用于加密,私钥用于解密。

虽然计算量大,但它解决了密钥分发的问题,特别适合设备初始化和密钥交换场景。

3.2.1 RSA 密钥交换

在物联网系统中,我们可以使用 RSA 进行密钥交换。

设备使用服务器的公钥加密一个随机生成的对称密钥,然后发送给服务器。

服务器用自己的私钥解密得到对称密钥,之后双方就可以使用这个对称密钥进行快速的 AES 加密通信了。

#include "mbedtls/rsa.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
​
// 使用RSA公钥加密AES密钥
int rsa_encrypt_session_key(const uint8_t* session_key, size_t key_len,
                            const mbedtls_rsa_context* rsa_public,
                            uint8_t* encrypted_key)
{
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    const char* pers = "rsa_encrypt";
    int ret;
    
    // 初始化随机数生成器
    mbedtls_entropy_init(&entropy);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                               (const uint8_t*)pers, strlen(pers));
    if (ret != 0) {
        goto cleanup;
    }
    
    // 使用RSA公钥加密
    ret = mbedtls_rsa_pkcs1_encrypt((mbedtls_rsa_context*)rsa_public,
                                   mbedtls_ctr_drbg_random, &ctr_drbg,
                                   MBEDTLS_RSA_PUBLIC, key_len,
                                   session_key, encrypted_key);
    
cleanup:
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    
    return ret;
}
​
// 使用RSA私钥解密AES密钥
int rsa_decrypt_session_key(const uint8_t* encrypted_key,
                            const mbedtls_rsa_context* rsa_private,
                            uint8_t* session_key, size_t* key_len)
{
    int ret;
    
    // 使用RSA私钥解密
    ret = mbedtls_rsa_pkcs1_decrypt((mbedtls_rsa_context*)rsa_private,
                                   NULL, NULL, MBEDTLS_RSA_PRIVATE,
                                   key_len, encrypted_key, session_key, 256);
    
    return ret;
}

3.3 轻量级加密算法

对于资源极度受限的设备,传统的 AES 和 RSA 可能都太"重"了。

这时候可以考虑专门为物联网设计的轻量级加密算法,比如 ChaCha20、Poly1305 等。

我在做一个基于 LoRa 的农业监测项目时,传感器节点使用的是 8 位单片机,只有 2KB 的 RAM。

在这种情况下,我们选择了 ChaCha20-Poly1305 算法,它在保证安全性的同时,对硬件资源的要求很低,而且性能优秀。

4. 安全通信协议

4.1 TLS/DTLS 协议

TLS(传输层安全协议)是互联网上使用最广泛的安全协议,HTTPS 就是基于 TLS 的。

对于物联网设备,如果使用 TCP 通信,可以采用 TLS;如果使用 UDP 通信(比如 CoAP 协议),则应该使用 DTLS(数据报传输层安全协议)。

在嵌入式 Linux 平台上,我们可以使用 OpenSSL 或 mbedTLS 库来实现 TLS 通信。

下面是一个使用 mbedTLS 建立 TLS 连接的简化示例:

#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
​
typedef struct {
    mbedtls_net_context net_ctx;
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_x509_crt cacert;
} tls_client_t;
​
// 初始化TLS客户端
int tls_client_init(tls_client_t* client, const char* ca_cert_pem)
{
    int ret;
    const char* pers = "tls_client";
    
    // 初始化上下文
    mbedtls_net_init(&client->net_ctx);
    mbedtls_ssl_init(&client->ssl);
    mbedtls_ssl_config_init(&client->conf);
    mbedtls_x509_crt_init(&client->cacert);
    mbedtls_ctr_drbg_init(&client->ctr_drbg);
    mbedtls_entropy_init(&client->entropy);
    
    // 初始化随机数生成器
    ret = mbedtls_ctr_drbg_seed(&client->ctr_drbg, mbedtls_entropy_func,
                               &client->entropy, (const uint8_t*)pers,
                               strlen(pers));
    if (ret != 0) {
        return ret;
    }
    
    // 加载CA证书
    ret = mbedtls_x509_crt_parse(&client->cacert,
                                (const uint8_t*)ca_cert_pem,
                                strlen(ca_cert_pem) + 1);
    if (ret != 0) {
        return ret;
    }
    
    // 配置SSL/TLS
    ret = mbedtls_ssl_config_defaults(&client->conf,
                                     MBEDTLS_SSL_IS_CLIENT,
                                     MBEDTLS_SSL_TRANSPORT_STREAM,
                                     MBEDTLS_SSL_PRESET_DEFAULT);
    if (ret != 0) {
        return ret;
    }
    
    mbedtls_ssl_conf_authmode(&client->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_ca_chain(&client->conf, &client->cacert, NULL);
    mbedtls_ssl_conf_rng(&client->conf, mbedtls_ctr_drbg_random,
                        &client->ctr_drbg);
    
    ret = mbedtls_ssl_setup(&client->ssl, &client->conf);
    if (ret != 0) {
        return ret;
    }
    
    return 0;
}
​
// 连接到服务器
int tls_client_connect(tls_client_t* client, const char* host, const char* port)
{
    int ret;
    
    // 建立TCP连接
    ret = mbedtls_net_connect(&client->net_ctx, host, port,
                             MBEDTLS_NET_PROTO_TCP);
    if (ret != 0) {
        return ret;
    }
    
    // 设置主机名(用于SNI)
    ret = mbedtls_ssl_set_hostname(&client->ssl, host);
    if (ret != 0) {
        return ret;
    }
    
    // 设置BIO回调
    mbedtls_ssl_set_bio(&client->ssl, &client->net_ctx,
                       mbedtls_net_send, mbedtls_net_recv, NULL);
    
    // 执行TLS握手
    while ((ret = mbedtls_ssl_handshake(&client->ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            return ret;
        }
    }
    
    // 验证服务器证书
    uint32_t flags = mbedtls_ssl_get_verify_result(&client->ssl);
    if (flags != 0) {
        return -1;
    }
    
    return 0;
}
​
// 发送数据
int tls_client_send(tls_client_t* client, const uint8_t* data, size_t len)
{
    int ret;
    size_t written = 0;
    
    while (written < len) {
        ret = mbedtls_ssl_write(&client->ssl, data + written, len - written);
        if (ret < 0) {
            if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
                ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
                return ret;
            }
        } else {
            written += ret;
        }
    }
    
    return written;
}
​
// 接收数据
int tls_client_recv(tls_client_t* client, uint8_t* buffer, size_t max_len)
{
    int ret;
    
    do {
        ret = mbedtls_ssl_read(&client->ssl, buffer, max_len);
    } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
             ret == MBEDTLS_ERR_SSL_WANT_WRITE);
    
    return ret;
}
​
// 关闭连接
void tls_client_close(tls_client_t* client)
{
    mbedtls_ssl_close_notify(&client->ssl);
    mbedtls_net_free(&client->net_ctx);
    mbedtls_x509_crt_free(&client->cacert);
    mbedtls_ssl_free(&client->ssl);
    mbedtls_ssl_config_free(&client->conf);
    mbedtls_ctr_drbg_free(&client->ctr_drbg);
    mbedtls_entropy_free(&client->entropy);
}

这个例子展示了如何使用 mbedTLS 库建立一个安全的 TLS 连接。

在实际应用中,设备会验证服务器的证书,确保连接到的是合法的服务器,而不是中间人攻击者。

4.2 MQTT 安全

MQTT 是物联网领域最流行的消息传输协议之一。

为了保证 MQTT 通信的安全,我们需要做以下几点:

4.2.1 使用 TLS 加密

MQTT over TLS(也叫 MQTTS)在标准 MQTT 协议的基础上增加了 TLS 加密层,端口通常是 8883。

这样可以防止消息被窃听和篡改。

4.2.2 用户名密码认证

MQTT 协议支持用户名和密码认证。

在连接到 MQTT Broker 时,客户端需要提供正确的用户名和密码。

但要注意,如果不使用 TLS,用户名密码会以明文传输,非常不安全。

4.2.3 客户端证书认证

更安全的做法是使用客户端证书认证。

每个 MQTT 客户端都有自己的证书和私钥,Broker 会验证客户端证书的有效性。

这种方式比用户名密码更安全,因为私钥不会在网络上传输。

我在一个工业物联网项目中就采用了这种方案。

每个传感器设备都有独立的证书,即使某个设备的证书泄露,也只影响这一个设备,不会波及整个系统。

而且我们可以随时吊销某个设备的证书,阻止它继续访问系统。

5. 安全启动和固件更新

5.1 安全启动(Secure Boot)

安全启动确保设备只运行经过授权的固件。

在设备启动时,Bootloader 会验证固件的数字签名,只有签名有效的固件才会被加载和执行。

STM32 等现代微控制器通常都支持安全启动功能。

以 STM32H7 为例,它提供了基于硬件的安全启动机制,可以在芯片内部验证固件签名,防止固件被篡改。

5.2 安全的固件更新(OTA)

物联网设备通常需要支持远程固件更新(OTA,Over-The-Air)。

但 OTA 过程如果不安全,可能成为攻击者的入口。一个安全的 OTA 流程应该包括:

5.2.1 固件签名验证

新固件必须经过数字签名,设备在更新前要验证签名的有效性。

这样可以确保固件来自可信的源,没有被篡改。

5.2.2 加密传输

固件在传输过程中应该加密,防止被截获和分析。

即使攻击者截获了固件,也无法解密其内容。

5.2.3 版本回滚保护

设备应该记录当前固件的版本号,拒绝安装旧版本的固件。

这样可以防止攻击者利用旧版本固件中的已知漏洞。

5.2.4 备份和恢复机制

在更新过程中如果出现问题(比如断电),设备应该能够恢复到之前的可用固件,而不是变成"砖头"。

通常的做法是使用双 Bank 存储,保留旧固件直到新固件验证成功。

下面是一个简化的 OTA 更新流程示例:

#include "stm32f4xx_hal.h"
#include "mbedtls/sha256.h"
#include "mbedtls/rsa.h"
​
#define FIRMWARE_BANK1_ADDR  0x08010000
#define FIRMWARE_BANK2_ADDR  0x08080000
#define FIRMWARE_MAX_SIZE    (448 * 1024)  // 448KB
​
typedef struct {
    uint32_t version;
    uint32_t size;
    uint8_t sha256[32];
    uint8_t signature[256];  // RSA-2048签名
} firmware_header_t;
​
// 验证固件签名
int verify_firmware_signature(const firmware_header_t* header,
                              const uint8_t* firmware_data,
                              const mbedtls_rsa_context* public_key)
{
    uint8_t hash[32];
    int ret;
    
    // 计算固件的SHA256哈希
    mbedtls_sha256_context sha256_ctx;
    mbedtls_sha256_init(&sha256_ctx);
    mbedtls_sha256_starts(&sha256_ctx, 0);
    mbedtls_sha256_update(&sha256_ctx, firmware_data, header->size);
    mbedtls_sha256_finish(&sha256_ctx, hash);
    mbedtls_sha256_free(&sha256_ctx);
    
    // 验证哈希值
    if (memcmp(hash, header->sha256, 32) != 0) {
        return -1;  // 哈希不匹配
    }
    
    // 验证RSA签名
    ret = mbedtls_rsa_pkcs1_verify((mbedtls_rsa_context*)public_key,
                                  NULL, NULL, MBEDTLS_RSA_PUBLIC,
                                  MBEDTLS_MD_SHA256, 32, hash,
                                  header->signature);
    
    return ret;
}
​
// OTA更新流程
int perform_ota_update(const uint8_t* new_firmware, size_t firmware_size,
                      const mbedtls_rsa_context* public_key)
{
    firmware_header_t* header = (firmware_header_t*)new_firmware;
    const uint8_t* firmware_data = new_firmware + sizeof(firmware_header_t);
    uint32_t current_version;
    HAL_StatusTypeDef status;
    
    // 读取当前固件版本
    current_version = *(uint32_t*)FIRMWARE_BANK1_ADDR;
    
    // 检查版本号(防止回滚攻击)
    if (header->version <= current_version) {
        return -1;  // 版本号不能降级
    }
    
    // 验证固件签名
    if (verify_firmware_signature(header, firmware_data, public_key) != 0) {
        return -2;  // 签名验证失败
    }
    
    // 解锁Flash
    HAL_FLASH_Unlock();
    
    // 擦除Bank2
    FLASH_EraseInitTypeDef erase_init;
    uint32_t page_error;
    erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
    erase_init.Sector = FLASH_SECTOR_8;  // Bank2起始扇区
    erase_init.NbSectors = 7;  // 擦除7个扇区
    erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3;
    
    status = HAL_FLASHEx_Erase(&erase_init, &page_error);
    if (status != HAL_OK) {
        HAL_FLASH_Lock();
        return -3;
    }
    
    // 写入新固件到Bank2
    uint32_t dest_addr = FIRMWARE_BANK2_ADDR;
    for (size_t i = 0; i < header->size; i += 4) {
        uint32_t data = *(uint32_t*)(firmware_data + i);
        status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, dest_addr, data);
        if (status != HAL_OK) {
            HAL_FLASH_Lock();
            return -4;
        }
        dest_addr += 4;
    }
    
    // 验证写入的数据
    if (memcmp((void*)FIRMWARE_BANK2_ADDR, firmware_data, header->size) != 0) {
        HAL_FLASH_Lock();
        return -5;  // 数据验证失败
    }
    
    // 锁定Flash
    HAL_FLASH_Lock();
    
    // 切换启动Bank(需要重启后生效)
    // 这里的实现取决于具体的MCU型号
    
    return 0;  // 更新成功
}

这个例子展示了一个完整的 OTA 更新流程,包括版本检查、签名验证、Flash 操作等。

在实际应用中,还需要考虑更多的细节,比如断电保护、进度报告、错误恢复等。

6. 安全存储

6.1 密钥存储

密钥是整个安全系统的基础,密钥一旦泄露,所有的安全措施都会失效。

因此,密钥的安全存储至关重要。

6.1.1 硬件安全模块

最安全的做法是使用专门的硬件安全模块(HSM)或安全元件(SE)来存储密钥。

这些硬件模块具有物理防护措施,密钥永远不会离开模块,所有的加密运算都在模块内部完成。

比如,STM32L5 系列微控制器集成了 TrustZone 技术,可以创建一个安全的执行环境,密钥存储在安全区域,普通应用无法访问。

我在一个支付终端项目中就使用了这种技术,确保支付密钥的绝对安全。

6.1.2 密钥派生

如果没有硬件安全模块,可以使用密钥派生函数(KDF)从一个主密钥派生出多个子密钥。

主密钥可以存储在芯片的 OTP(一次性可编程)区域或加密的 Flash 中,子密钥在需要时动态生成,用完就销毁,不在内存中长期保存。

6.2 敏感数据保护

除了密钥,设备可能还需要存储其他敏感数据,比如用户密码、配置参数等。

这些数据也应该加密存储,防止被读取。

我在做一个智能门锁项目时,用户的指纹模板就是加密存储在 Flash 中的。

即使有人拆开门锁读取 Flash 内容,也无法获得原始的指纹数据。

7. 安全开发实践

7.1 最小权限原则

设备和应用应该只拥有完成任务所必需的最小权限。

比如,一个温度传感器只需要上报温度数据的权限,不应该有控制其他设备或修改系统配置的权限。

在设计物联网系统时,我会为不同类型的设备分配不同的角色和权限。

传感器只能发布数据,不能订阅控制指令;控制器可以发布控制指令,但不能修改设备配置;管理员账户才有完全的权限。

这种分层的权限管理大大降低了安全风险。

7.2 输入验证

永远不要信任外部输入。

所有从网络、用户界面、传感器等外部来源的数据,都应该经过严格的验证和过滤,防止注入攻击、缓冲区溢出等安全问题。

我在代码中会对所有的输入数据进行边界检查、类型检查、格式检查等。

比如,如果期望接收一个 0-100 的温度值,那么超出这个范围的数据就应该被拒绝。

看似简单的检查,却能避免很多潜在的安全问题。

7.3 安全日志

记录详细的安全日志对于发现和追踪安全事件非常重要。

日志应该包括认证失败、异常访问、配置变更等关键事件。

但要注意,日志中不应该包含敏感信息,比如密码、密钥等。

在我负责的项目中,所有的安全事件都会被记录并上传到云端。

一旦检测到异常模式(比如短时间内大量的认证失败),系统会自动告警,管理员可以及时采取措施。

7.4 定期安全审计

安全不是一次性的工作,而是一个持续的过程。

应该定期对系统进行安全审计,检查是否有新的漏洞,是否有配置不当的地方。

同时,要及时关注安全公告,一旦发现使用的库或组件有安全漏洞,要尽快更新。

我的团队每个季度都会进行一次安全审计,包括代码审查、渗透测试、漏洞扫描等。

虽然这会占用一些开发时间,但能够及早发现和修复安全问题,避免更大的损失。

8. 总结

物联网安全是一个复杂而重要的话题,涉及到硬件、软件、网络、密码学等多个领域。

作为嵌入式开发者,我们需要从设计之初就将安全纳入考虑,而不是事后补救。

在我多年的物联网开发经验中,深刻体会到安全和便利性往往是矛盾的。

过于严格的安全措施会影响用户体验,但过于宽松又会带来安全风险。

关键是要根据实际应用场景,在安全性和可用性之间找到平衡点。

对于智能门锁、医疗设备、工业控制等安全关键型应用,应该采用最高级别的安全措施,不惜牺牲一些便利性。

而对于一般的消费类产品,可以适当简化安全机制,但基本的加密和认证是必不可少的。

最后,安全是一个持续演进的过程。今天安全的系统,明天可能就会出现新的漏洞。

我们需要保持学习,关注安全动态,不断改进和完善我们的产品。

只有这样,才能在物联网时代为用户提供真正安全可靠的服务。

更多编程学习资源

基于YOLOv8的道路隐患识别与城市路况安全识别|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!

本项目基于 YOLOv8 深度学习目标检测模型,结合 PyQt5 图形界面工具,实现了面向城市道路的隐患设施识别与路况安全检测系统。系统能够高效识别包括井盖、打开的井盖、道路坑洞、减速带及无标识减速带在内的常见道路设施及潜在安全隐患。

项目特色在于:

  • 提供 完整数据集及标注,便于直接训练与微调模型。
  • 内置 YOLOv8训练与推理代码,支持自定义训练与快速部署。
  • 提供 PyQt5可视化界面,支持图片、文件夹、视频以及实时摄像头输入。
  • 配套 开箱即用的权重文件 和详细部署/训练教程,降低模型应用门槛。

该系统可广泛应用于智能交通巡检、城市道路安全管理、自动驾驶环境感知等场景,为提升道路安全和管理效率提供数据与技术支撑。

基本功能演示

https://www.bilibili.com/video/BV1CT65BLE7h/

源码在文末哔哩哔哩视频简介处获取。

包含:

📦完整项目源码

📦 预训练模型权重

🗂️ 数据集地址(含标注脚本)

前言

随着城市道路设施数量的增加与道路交通复杂度的提升,道路隐患识别与安全监测变得尤为重要。传统人工巡检效率低、成本高且存在疏漏,而深度学习目标检测技术的发展为道路安全监控提供了智能化解决方案。

YOLOv8 作为当前性能优异的实时目标检测模型,具有高精度和低延迟的优势,特别适合道路设施和隐患目标的检测任务。结合 PyQt5 图形界面,本项目实现了从数据标注、模型训练到可视化检测的一体化解决方案,使用户无需复杂配置即可快速部署道路安全检测系统。

本项目旨在提供一套完整的 “数据集+模型训练+推理部署+图形界面工具” 流程,降低道路安全检测系统的实现门槛,同时为科研、城市管理及智能交通领域提供可落地的参考方案。

一、软件核心功能介绍及效果演示

多目标检测能力

  • 支持 5 类道路设施和隐患目标:井盖(Manhole)、打开井盖(Open Manhole)、道路坑洞(Pothole)、减速带(Speed Bump)、无标识减速带(Unmarked Bump)。
  • 采用 YOLOv8 模型,实现快速且精准的目标检测。

多输入模式支持

  • 图片单张检测
  • 文件夹批量检测
  • 视频文件检测
  • 实时摄像头流检测

图形化交互界面

  • PyQt5 界面,可直接拖拽文件进行检测
  • 可视化显示检测结果及置信度
  • 支持结果导出与标注可视化

完整训练与部署流程

  • 提供训练代码与数据集,支持自定义模型训练
  • 提供预训练权重文件,实现开箱即用的检测效果
  • 提供详细部署教程,轻松在本地或服务器环境运行

实时性能与可扩展性

  • YOLOv8 模型保证高帧率检测,适合视频与摄像头实时应用
  • 支持自定义类别扩展和迁移训练,方便后续功能升级

二、软件效果演示

为了直观展示本系统基于 YOLOv8 模型的检测能力,我们设计了多种操作场景,涵盖静态图片、批量图片、视频以及实时摄像头流的检测演示。

(1)单图片检测演示

用户点击“选择图片”,即可加载本地图像并执行检测:

image-20260128011805354


(2)多文件夹图片检测演示

用户可选择包含多张图像的文件夹,系统会批量检测并生成结果图。

image-20260128011953115

image-20260128012033275


(3)视频检测演示

支持上传视频文件,系统会逐帧处理并生成目标检测结果,可选保存输出视频:

image-20260128012047038


(4)摄像头检测演示

实时检测是系统中的核心应用之一,系统可直接调用摄像头进行检测。由于原理和视频检测相同,就不重复演示了。

image-20260128012106312


(5)保存图片与视频检测结果

用户可通过按钮勾选是否保存检测结果,所有检测图像自动加框标注并保存至指定文件夹,支持后续数据分析与复审。

image-20260128012124698

三、模型的训练、评估与推理

YOLOv8是Ultralytics公司发布的新一代目标检测模型,采用更轻量的架构、更先进的损失函数(如CIoU、TaskAlignedAssigner)与Anchor-Free策略,在COCO等数据集上表现优异。
其核心优势如下:

  • 高速推理,适合实时检测任务
  • 支持Anchor-Free检测
  • 支持可扩展的Backbone和Neck结构
  • 原生支持ONNX导出与部署

3.1 YOLOv8的基本原理

YOLOv8 是 Ultralytics 发布的新一代实时目标检测模型,具备如下优势:

  • 速度快:推理速度提升明显;
  • 准确率高:支持 Anchor-Free 架构;
  • 支持分类/检测/分割/姿态多任务
  • 本项目使用 YOLOv8 的 Detection 分支,训练时每类表情均标注为独立目标。

YOLOv8 由Ultralytics 于 2023 年 1 月 10 日发布,在准确性和速度方面具有尖端性能。在以往YOLO 版本的基础上,YOLOv8 引入了新的功能和优化,使其成为广泛应用中各种物体检测任务的理想选择。

image-20250526165954475

YOLOv8原理图如下:

image-20250526170118103

3.2 数据集准备与训练

采用 YOLO 格式的数据集结构如下:

dataset/
├── images/
│   ├── train/
│   └── val/
├── labels/
│   ├── train/
│   └── val/

每张图像有对应的 .txt 文件,内容格式为:

4 0.5096721233576642 0.352838390077821 0.3947600423357664 0.31825755058365757

分类包括(可自定义):

image-20260128012225839

3.3. 训练结果评估

训练完成后,将在 runs/detect/train 目录生成结果文件,包括:

  • results.png:损失曲线和 mAP 曲线;
  • weights/best.pt:最佳模型权重;
  • confusion_matrix.png:混淆矩阵分析图。
若 mAP@0.5 达到 90% 以上,即可用于部署。

在深度学习领域,我们通常通过观察损失函数下降的曲线来评估模型的训练状态。YOLOv8训练过程中,主要包含三种损失:定位损失(box_loss)、分类损失(cls_loss)和动态特征损失(dfl_loss)。训练完成后,相关的训练记录和结果文件会保存在runs/目录下,具体内容如下:

image-20260128012242496

3.4检测结果识别

使用 PyTorch 推理接口加载模型:

import cv2
from ultralytics import YOLO
import torch
from torch.serialization import safe_globals
from ultralytics.nn.tasks import DetectionModel

# 加入可信模型结构
safe_globals().add(DetectionModel)

# 加载模型并推理
model = YOLO('runs/detect/train/weights/best.pt')
results = model('test.jpg', save=True, conf=0.25)

# 获取保存后的图像路径
# 默认保存到 runs/detect/predict/ 目录
save_path = results[0].save_dir / results[0].path.name

# 使用 OpenCV 加载并显示图像
img = cv2.imread(str(save_path))
cv2.imshow('Detection Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

预测结果包含类别、置信度、边框坐标等信息。

image-20260128012301427

四.YOLOV8+YOLOUI完整源码打包

本文涉及到的完整全部程序文件:包括python源码、数据集、训练代码、UI文件、测试图片视频等(见下图):

4.1 项目开箱即用

作者已将整个工程打包。包含已训练完成的权重,读者可不用自行训练直接运行检测。

运行项目只需输入下面命令。

python main.py

读者也可自行配置训练集,或使用打包好的数据集直接训练。

自行训练项目只需输入下面命令。

yolo detect train data=datasets/expression/loopy.yaml model=yolov8n.yaml pretrained=yolov8n.pt epochs=100 batch=16 lr0=0.001

总结

本项目基于 YOLOv8 目标检测模型与 PyQt5 图形界面,实现了面向城市道路的 隐患设施识别与路况安全检测系统。系统支持图片、视频、摄像头及批量文件夹多种输入模式,能够快速识别井盖、打开的井盖、道路坑洞、减速带及无标识减速带等道路设施和潜在安全隐患。

项目特点在于提供 完整数据集及标注、训练代码、预训练权重和部署教程,用户可直接开箱使用或进行自定义训练。该系统兼具 高精度识别、实时性能和易用性,可广泛应用于智能交通巡检、城市道路安全管理及自动驾驶环境感知等场景,为提升城市道路安全和管理效率提供数据和技术支撑。

应届生,即将从事 AI 相关的行业。

感觉这个行业离开了大公司没有就没有生存空间了,对未来很迷茫,靠上班也不可能实现财富自由,这个行业还不知道能干几年。

我觉得自己本身是喜欢计算机,喜欢写出一些小东西的,就一直想着找个需求写点小工具,但是每次想到的最后会发现市面上成熟的工具都已经非常多了,说到底还是自己周围的需求太直接了,大家早就做过了。不知道如何去发掘新需求,或者有什么更合适的副业?(感觉自己因为焦虑有点不愿意让自己闲下来,哎