Winform+MQTTnet自托管通信与消息持久化实战
简介本资源是一套基于WinForm平台的MQTT通信完整示例工程面向C#初学者及物联网应用开发人员解决MQTT协议在桌面端服务端与客户端双向通信、消息持久化等核心实践问题。压缩包共67个文件涵盖10个关键DLL含MQTTnet核心库、8个C#源码文件含服务端Program.cs、客户端Form1.cs等、4个可执行EXE便于直接运行验证、2个SLN/CSProj项目文件支持VS快速加载以及JSON配置、日志缓存和构建辅助文件整体仅494KB轻量易部署。已有2133人学习下载代码结构清晰分层服务端可独立启动监听客户端支持连接、订阅、接收并自动将消息追加保存至本地文本文件附带完整VS解决方案与调试配置开箱即用适合快速理解MQTTnet API调用流程、消息序列化机制及WinForm异步通信设计模式。1. Winform MQTTnet 实现端到端通信一个能跑通、能存档、能调试的完整闭环你有没有遇到过这种场景在工业现场用 Winform 做上位机设备通过 MQTT 上报温湿度、开关状态但手头只有零散的客户端示例服务端要么得装 Mosquitto、要么得配 Docker一上真机就卡在 TLS 证书或端口占用上更头疼的是领导突然说“把过去24小时所有报警消息导出成文本备查”——这时候你才发现订阅的消息全在内存里闪一下就没了连个落盘逻辑都没有。这个.rar包就是为这类真实工控场景准备的它不依赖外部 Broker用 MQTTnet 自托管一个轻量服务端Winform 客户端支持连接/订阅/发布三件套最关键的是所有Subscribe到的主题消息会按主题名自动分文件、带时间戳写入 UTF-8 文本支持断线重连后追加续写。适合某高校实验室做传感器网关 Demo、某公司产线数据采集模块原型开发也适合刚学完 C# 基础想落地物联网通信的新手——它把“MQTT 是什么”直接翻译成了“双击 exe 就能看收发日志”的可执行体。2. 为什么选 MQTTnet 而不是官方库或自建 TCP三个硬核理由与架构拆解2.1 MQTTnet 的不可替代性纯 .NET 实现 零依赖 真异步MQTTnet 不是简单封装 System.Net.Sockets 的胶水层而是从协议解析器开始重写的全栈实现。它的MqttFactory类内部做了三件关键事字节流预解析收到原始 TCP 数据包后先校验固定头Fixed Header的Remaining Length字段是否合法再动态分配缓冲区避免大消息导致OutOfMemoryExceptionQoS 分级调度QoS0 消息走无锁队列直发QoS1 会生成PacketIdentifier并维护PendingPublishes字典超时未 ACK 时自动重传QoS2 则启用PubRec/PubRel/PubComp三阶段确认状态机跨平台兼容性同一份代码在 .NET Framework 4.6.1 和 .NET 6 下行为一致不像某些老库在 Winform 中调用async void导致 UI 线程死锁。提示项目中服务端使用MqttServerOptionsBuilder启用WithDefaultEndpointPort(1883)但实际部署时建议改为1884或更高端口——避开 Windows 默认防火墙对 1883 的拦截策略这是某导师在某跨平台系统中踩过的坑。2.2 架构图服务端、客户端、文件存储三模块如何耦合整个方案采用松耦合分层设计各模块职责清晰模块核心类职责关键参数服务端MqttFactory.CreateServer()监听 TCP 连接、处理 CONNECT/PUBLISH/SUBSCRIBE 协议帧、维护 ClientId 会话状态ConnectionBacklog100,MaxPendingMessagesPerClient500客户端MqttFactory.CreateManagedClient()封装重连逻辑、心跳保活KeepAlivePeriod30s、离线消息缓存AutoReconnectDelayTimeSpan.FromSeconds(2)文件存储MessageFileWriter自定义类按topic/yyyy-MM-dd_HH.txt规则生成路径每条消息前缀添加[yyyy-MM-dd HH:mm:ss.fff]MaxFileSizeBytes10*1024*102410MB这种设计让调试变得极其直观当客户端连不上时先看服务端控制台是否打印Client connected: client1消息收不到时检查MessageFileWriter是否抛出UnauthorizedAccessException常因目录权限不足而不用像某些黑匣子方案那样得抓包分析 MQTT 协议字段。2.3 服务端启动从空壳到可连接的 5 行核心代码服务端逻辑全部封装在MqttServerHost类中启动入口仅需以下代码// Program.cs 中的 Main 方法 var options new MqttServerOptionsBuilder() .WithDefaultEndpointPort(1883) // 生产环境建议改端口 .WithConnectionValidator(c { // 允许任意 ClientId 连接测试用生产环境应校验用户名密码 c.ReturnCode MqttConnectReturnCode.ConnectionAccepted; }) .Build(); var server new MqttFactory().CreateServer(options); server.StartedAsync (s, e) Console.WriteLine(MQTT 服务端已启动); await server.StartAsync(); // 阻塞式启动异常会在此处抛出这段代码背后藏着几个关键决策点WithConnectionValidator回调中直接设ReturnCode跳过了标准的Username/Password校验流程——因为 Winform 客户端通常运行在可信内网加认证反而增加调试复杂度StartedAsync事件用于确认服务端真正进入监听状态比单纯await server.StartAsync()更可靠避免客户端在服务端初始化完成前就发起连接若需 TLS 支持只需将WithDefaultEndpointPort替换为WithTlsEndpoint并传入X509Certificate2实例但本示例暂不启用否则新手容易卡在证书生成环节。3. 客户端实战连接、订阅、发布、断线重连四步法3.1 连接配置为什么ManagedMqttClient比MqttClient更适合 WinformWinform 应用最怕阻塞 UI 线程。原生MqttClient的ConnectAsync是纯异步但若在按钮点击事件中直接await client.ConnectAsync()UI 仍可能短暂卡顿。而ManagedMqttClient内置了后台任务调度器// Form1.cs 初始化客户端 private readonly IMqttClient _client; private readonly MqttFactory _factory; public Form1() { InitializeComponent(); _factory new MqttFactory(); _client _factory.CreateManagedClient(new ManagedMqttClientOptions { ClientOptions new MqttClientOptionsBuilder() .WithClientId(winform_client_ Guid.NewGuid().ToString(N).Substring(0, 8)) .WithTcpServer(127.0.0.1, 1883) .WithCleanSession() // 断开后清除服务端会话 .Build(), // 自动重连策略首次延迟2秒后续指数退避至30秒 AutomaticReconnectDelay TimeSpan.FromSeconds(2) }); }这里的关键参数是AutomaticReconnectDelay它不是固定间隔重试而是每次失败后等待时间翻倍2s → 4s → 8s…直到达到上限。这比写死Thread.Sleep(2000)更符合网络抖动的真实场景。3.2 订阅消息如何避免“订阅成功但收不到消息”的玄学问题订阅逻辑看似简单但有三个隐藏雷区// 订阅指定主题例如 sensor/temperature await _client.SubscribeAsync(new TopicFilterBuilder() .WithTopic(sensor/temperature) .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce) // QoS0 最常用 .Build()); // 必须注册消息到达事件处理器 _client.ApplicationMessageReceivedAsync async e { var topic e.ApplicationMessage.Topic; var payload Encoding.UTF8.GetString(e.ApplicationMessage.Payload); var timestamp DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss.fff); // 调用文件写入器见第4章 await MessageFileWriter.AppendToFileAsync(topic, $[{timestamp}] {payload}); };现象 → 原因 → 解决现象控制台显示Subscribed to sensor/temperature但发布消息后ApplicationMessageReceivedAsync从未触发原因ApplicationMessageReceivedAsync事件注册必须在SubscribeAsync之后且不能放在Form_Load中此时_client可能未完全初始化解决将订阅和事件注册合并到一个ConnectAndSubscribe()方法中并在ConnectedAsync事件回调里调用。3.3 发布消息带时间戳的 JSON 格式约定与编码陷阱客户端发布时强烈建议统一消息格式方便后续解析private async void btnPublish_Click(object sender, EventArgs e) { var message new { timestamp DateTime.UtcNow.ToString(o), // ISO 8601 格式 device_id sensor_001, value txtValue.Text, unit °C }; var payload Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message)); await _client.PublishAsync(new MqttApplicationMessageBuilder() .WithTopic(sensor/temperature) .WithPayload(payload) .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce) .WithRetain(false) // 测试阶段禁用 Retain避免旧消息干扰 .Build()); }注意Encoding.UTF8.GetBytes()的调用时机必须在JsonSerializer.Serialize()之后。如果先new byte[1024]再Encoding.UTF8.GetBytes(...)会导致字节数组长度错误服务端解析失败。3.4 断线重连验证用防火墙模拟真实网络中断手动验证重连逻辑最有效的方法是临时禁用本地端口# Windows PowerShell管理员权限 netsh advfirewall firewall add rule nameBlock MQTT dirin actionblock protocolTCP localport1883 # 等待客户端显示 Disconnected 日志后再删除规则 netsh advfirewall firewall delete rule nameBlock MQTT此时观察客户端日志第一次断开后DisconnectedAsync事件触发日志输出Connection lost, retrying in 2s...重连成功后ConnectedAsync触发并自动重新订阅之前的所有 TopicManagedMqttClient内置行为服务端控制台会打印Client reconnected: winform_client_xxx而非新连接。4. 消息持久化按主题分文件、带时间戳、防乱码的落盘方案4.1 文件路径生成规则为什么不用DateTime.Now.ToString(yyyyMMdd)初学者常犯的错误是把日期直接拼进文件名导致跨天时文件切换不及时// ❌ 错误示范DateTime.Now 在构造函数中只执行一次 private readonly string _fileName $log_{DateTime.Now:yyyyMMdd}.txt; // ✅ 正确做法每次写入前动态计算 private string GetLogFileName(string topic) { var datePart DateTime.Now.ToString(yyyy-MM-dd); var cleanTopic topic.Replace(/, _).Replace(, wildcard).Replace(#, multi); return Path.Combine(logs, ${cleanTopic}_{datePart}.txt); }cleanTopic的替换逻辑很重要MQTT 主题中的/在 Windows 路径中非法和#是通配符必须转义否则sensor/会被写成sensor_wildcard_2024-04-01.txt避免后续按主题检索时混淆。4.2 线程安全写入ConcurrentQueue 后台任务的低开销方案高频消息场景下直接File.AppendAllText()会导致 IO 瓶颈。本方案采用生产者-消费者模型public static class MessageFileWriter { private static readonly ConcurrentQueue(string Topic, string Content) _writeQueue new ConcurrentQueue(string, string)(); static MessageFileWriter() { // 启动后台写入任务单例 Task.Run(async () { while (true) { if (_writeQueue.TryDequeue(out var item)) { try { var filePath GetLogFileName(item.Topic); Directory.CreateDirectory(Path.GetDirectoryName(filePath)); await File.AppendAllTextAsync(filePath, item.Content Environment.NewLine); } catch (Exception ex) { // 记录错误但不中断队列避免消息丢失 Debug.WriteLine($Write failed: {ex.Message}); } } else { await Task.Delay(10); // 空闲时降低 CPU 占用 } } }); } public static async Task AppendToFileAsync(string topic, string content) { _writeQueue.Enqueue((topic, content)); } }这个设计的好处是即使AppendToFileAsync被每秒调用 1000 次实际磁盘 IO 由后台任务以批处理方式完成UI 线程完全不受影响。4.3 防乱码终极方案BOM 头与编码强制声明Windows 记事本打开 UTF-8 文件时经常显示乱码根源在于缺少 BOMByte Order Mark。解决方案是在首次创建文件时写入 BOMprivate static async Task EnsureFileHasUtf8Bom(string filePath) { if (!File.Exists(filePath)) { // 创建文件并写入 UTF-8 BOMEF BB BF using var fs File.Create(filePath); await fs.WriteAsync(new byte[] { 0xEF, 0xBB, 0xBF }, 0, 3); } }调用位置在AppendToFileAsync中Directory.CreateDirectory之后、File.AppendAllTextAsync之前插入此方法。这样生成的.txt文件用记事本、VS Code、Notepad 打开均能正确识别编码。5. 避坑指南五个血泪经验总结的高频翻车点5.1 现象服务端启动时报错 “Address already in use”但netstat -ano查不到占用进程原因Windows 10/11 启用了“Hyper-V”或“WSL2”它们会默认监听 1883 端口即使没运行任何服务。解决临时方案修改服务端端口为1884彻底方案以管理员身份运行 PowerShell执行netsh interface ipv4 set excludedportrange protocoltcp startport1883 numberofports1然后重启系统。5.2 现象客户端能连接、能发布但订阅的消息始终不触发ApplicationMessageReceivedAsync原因服务端WithConnectionValidator中未设置c.ReturnCode MqttConnectReturnCode.ConnectionAccepted;默认返回UnacceptableProtocolVersion。解决检查服务端启动代码确保ConnectionValidator回调中显式赋值不能只写{ }空块。5.3 现象消息写入文件后中文显示为? ? ?或方块原因File.AppendAllTextAsync默认使用UTF-8但不带 BOM而 Windows 记事本默认按 ANSI 解码。解决按 4.3 节方案在文件首次创建时写入 BOM或改用StreamWriter显式指定编码using var writer new StreamWriter(filePath, true) { Encoding Encoding.UTF8 }; await writer.WriteLineAsync(content);5.4 现象Winform 窗体关闭后服务端仍在后台运行无法彻底退出原因MqttServer.StartAsync()是Task但未被CancellationToken关联Application.Exit()不会主动取消它。解决在窗体FormClosing事件中添加private async void Form1_FormClosing(object sender, FormClosingEventArgs e) { await _server.StopAsync(); // _server 是服务端实例 await Task.Delay(100); // 确保停止完成 }5.5 现象发布 QoS1 消息后服务端日志显示PUBACK received但客户端PublishAsync一直不返回原因客户端MqttClientOptions中未设置KeepAlivePeriod导致服务端在 60 秒无心跳后主动断开连接PUBACK无法送达。解决在客户端配置中显式设置.WithKeepAlivePeriod(TimeSpan.FromSeconds(30))6. 进阶技巧用 Wireshark 抓包验证 MQTT 协议合规性与性能压测6.1 Wireshark 过滤规则精准定位 MQTT 流量安装 Wireshark 后启动服务端和客户端然后在捕获过滤器中输入tcp.port 1883 ip.addr 127.0.0.1应用显示过滤器mqtt mqtt.msgtype 1 # CONNECT mqtt mqtt.msgtype 3 # PUBLISH mqtt mqtt.msgtype 4 # PUBACK这样就能单独查看 CONNECT 握手包、PUBLISH 消息体、PUBACK 确认帧验证 QoS1 是否真的完成了三次握手。6.2 性能压测用 Python 脚本模拟 100 个并发客户端虽然本项目面向 Winform 单机场景但验证服务端承载能力很有必要。用 Python 的paho-mqtt写一个轻量压测脚本# stress_test.py import paho.mqtt.client as mqtt import threading import time def client_loop(client_id): client mqtt.Client(client_id) client.connect(127.0.0.1, 1883, 60) for i in range(50): # 每个客户端发50条 client.publish(ftest/{client_id}, fmsg_{i}, qos0) time.sleep(0.01) client.disconnect() # 启动100个线程 threads [] for i in range(100): t threading.Thread(targetclient_loop, args(fstress_{i},)) threads.append(t) t.start() for t in threads: t.join() print(压测完成)运行后观察服务端控制台若出现大量Client disconnected unexpectedly说明MaxPendingMessagesPerClient设置过小需调高若 CPU 持续 80%则需检查MessageFileWriter的队列消费速度是否跟得上。6.3 消息回溯从文件快速定位某时间段的特定设备数据假设要查sensor_001在2024-04-01 14:00~15:00的所有温度记录直接用 PowerShell 一行搞定Select-String -Path logs\sensor_temperature_2024-04-01.txt -Pattern \[2024-04-01 14:[0-5][0-9]:[0-5][0-9]\.[0-9]{3}\].*sensor_001 -AllMatches | ForEach-Object { $_.Line }这个命令利用正则精确匹配时间范围14:[0-5][0-9]匹配 14:00~14:59比用 Excel 手动筛选快十倍。某公司产线故障复盘时就是靠这个技巧在 3 分钟内定位到异常升温起始点。从那以后我每次交付 Winform 物联网模块都强制走一遍「Wireshark 抓包验证 PowerShell 时间段检索」双校验流程——既堵住协议层漏洞又确保业务数据可追溯。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Quick Report 4.05 源码编译与二次开发实战:从环境搭建到套打定位

Quick Report 4.05 源码编译与二次开发实战:从环境搭建到套打定位

简介:Quick Report 4.05 是面向 BCB6(Borland C Builder 6)与 Delphi 7 开发者的报表生成控件包,主要解决可视化报表设计、打印预览与自定义纸张打印等场景中的布局与精度问题。资源以完整源码形式提供,适合需要将报表…

2026/10/19 12:17:30 阅读更多 →
战场烟雾火焰数据集:xml与txt标注格式解析及YOLO训练实战

战场烟雾火焰数据集:xml与txt标注格式解析及YOLO训练实战

简介:这份数据集面向从事目标检测算法研究与改进的开发者,聚焦战争场景中导弹发射、导弹爆炸产生的烟雾与火焰识别任务。数据主要从视频中抽帧制作,共包含923幅1280720分辨率的影像,标注覆盖烟雾(smoke)与火…

2026/10/19 12:17:30 阅读更多 →
从正则表达式到NFA/DFA:词法分析器核心构造全解析

从正则表达式到NFA/DFA:词法分析器核心构造全解析

如果你正在啃词法分析这一块,那么NFA和DFA这两个缩写迟早会出现在你面前。它们的全称是非确定有限自动机和确定有限自动机,名字拗口,但核心问题只有一个:如何让程序在输入流上自动判断出“下一个字符序列属于哪个token”。上一篇笔…

2026/10/19 12:17:30 阅读更多 →

最新新闻

工业时序预测实战:基于CNN-BiLSTM-Attention的三模态融合模型

工业时序预测实战:基于CNN-BiLSTM-Attention的三模态融合模型

1. 三模态融合的架构设计与选型理由1.1 为什么偏偏是CNN、BiLSTM、Attention三件套工业时序预测(比如设备剩余寿命预测、关键部件温度趋势预估、整线能耗滚动预报)有一个共性痛点:数据维度高、噪声大、时间依赖长,单靠一种模型总是…

2026/10/19 12:59:13 阅读更多 →
在Claude Code和Codex之上加一层决策层:让Coding Agent从碰运气变可预期

在Claude Code和Codex之上加一层决策层:让Coding Agent从碰运气变可预期

1. 为什么要在 Claude Code 和 Codex 之上再叠一层决策层先说结论:单纯把 Claude Code 或 Codex 接进工作流,能解决"写代码"的问题,但解决不了"该不该写、先写哪块、写到什么程度停手"的问题。Jev 这个项目要做的&#x…

2026/10/19 12:59:13 阅读更多 →
CMake target_link_libraries签名冲突:openvslam报错定位与统一修复

CMake target_link_libraries签名冲突:openvslam报错定位与统一修复

1. 问题背景与核心症结拆解1.1 这个报错到底在说什么做过C项目构建的人,大概率都在CMake这个环节栽过跟头。The plain signature for target_link_libraries has already been used with the target "openvslam"这个报错,字面意思很直白&#…

2026/10/19 12:59:13 阅读更多 →
bypy百度网盘命令行工具实战指南

bypy百度网盘命令行工具实战指南

1. 为什么非得在命令行里碰百度网盘?——一个被低估的生产力缺口你有没有过这种时刻:深夜改完一份200MB的实验数据集,想传给合作者,但图形界面的百度网盘客户端卡在“正在扫描文件”上纹丝不动;或者在一台没有桌面环境…

2026/10/19 12:59:13 阅读更多 →
远程驾驶技术解析:Vay基于NVIDIA DRIVE AGX的算力与安全架构

远程驾驶技术解析:Vay基于NVIDIA DRIVE AGX的算力与安全架构

1. “没有司机的车”背后,其实是远程司机在开车 最近两年,自动驾驶行业里出现了一种和“全无人Robotaxi”并行的路线—— 远程驾驶(Teledriving) 。Vay这家公司主推的就是这个方向:车辆本身具备一定感知和计算能力&a…

2026/10/19 12:59:13 阅读更多 →
机器人技术十年演进:从运动控制到具身智能的核心脉络

机器人技术十年演进:从运动控制到具身智能的核心脉络

1. 十年,机器人技术到底变了什么 翻了翻过去十年的项目笔记,最早接触机器人还是在实验室里调试一台六轴机械臂,用的还是古老的示教器,一点一点把轨迹录进去,机器人一遍一遍地重复执行。那时候谁能想到,十年…

2026/10/19 12:58:11 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →