Qt低功耗蓝牙开发实战:从GATT通信到MTU协商与Notify订阅
简介本资源是一套基于Qt框架的低功耗蓝牙BLE特征值读写测试例程面向嵌入式开发、物联网应用及跨平台桌面端BLE通信初学者与进阶开发者解决BLE设备调试中服务发现、GATT特征交互、异步读写响应等核心实践难点。压缩包为9KB的ZIP文件共11个文件涵盖3个CPP源码含主程序与BLE控制器逻辑、2个H头文件定义蓝牙通信接口、1个UI界面文件Qt Designer设计、1个PRO工程配置及PRI模块引入文件辅以README说明与Git管理文件结构精简、开箱即用。已有940人学习下载可直接编译运行完整呈现QBluetoothDeviceDiscoveryAgent扫描、QBluetoothGattService服务获取、QBluetoothGattCharacteristic特征值读写及信号回调处理全流程代码注释清晰适合作为BLE通信原理验证与Qt Bluetooth API入门实践范例。1. Qt 低功耗蓝牙测试例程不是“连上就行”而是把特征值读写踩进硬件时序缝里你手头有一块带 BLE 的嵌入式板子用 Qt 写了个 App 想读个电池电量0x2A19、写个控制指令0x2A06结果QBluetoothUuid构造对了、QBluetoothService发现成功了、QBluetoothCharacteristic也拿到了——可read()返回空、write()后设备毫无反应。这不是 Qt 不行是 BLE 协议栈在底层悄悄卡住了GATT 事务未确认、MTU 未协商、写类型with response / without response选错、甚至特征值权限Read/Write/Notify在服务端根本没开。这个 Qt 低功耗蓝牙测试例程就是专治这种“逻辑通、物理断”的玄学问题——它不只演示 API 调用而是把QBluetoothDeviceDiscoveryAgent→QBluetoothSocket或QLowEnergyController→QLowEnergyService→QLowEnergyCharacteristic这条链路上每个环节的状态机跳转条件、超时阈值、错误码映射、重试策略全摊开实测过。适合正在调试 BLE 外设通信的 Qt 开发者、嵌入式 Qt GUI 工程师以及被CharacteristicWriteError和InvalidAttributeValueError折磨到想砸开发板的硬件联调人员。2. 为什么必须用 QLowEnergyController 而非 QBluetoothSocketBLE 与经典蓝牙的本质分叉Qt 的蓝牙模块表面看是统一 API但底层实现天差地别。QBluetoothSocket面向经典蓝牙BR/EDR走 RFCOMM 通道建立的是面向连接的流式传输而低功耗蓝牙BLE本质是 GATT 客户端-服务器模型所有操作基于属性协议ATT依赖连接间隔Connection Interval、从设备延迟Slave Latency、监控超时Supervision Timeout三参数协同。QLowEnergyController才是 Qt 官方为 BLE 设计的专用控制器它直接封装了 Linux BlueZ 的org.bluez.LEAdvertisingManager1和org.bluez.GattClient1接口能精确控制连接参数、处理 ATT 错误响应、监听serviceDiscovered()和characteristicChanged()信号——这些是QBluetoothSocket根本不具备的能力。2.1 从设备发现到连接状态机驱动的可靠建链流程BLE 连接不是“connect() 一下就通”而是一系列异步状态跃迁。该例程强制采用状态机管理避免开发者在connected()信号里直接调用discoverServices()导致未就绪报错// 状态枚举定义关键避免 magic number enum class BleState { Idle, Discovering, Connecting, ServiceDiscovery, CharacteristicDiscovery, Ready, Error }; // 连接流程核心逻辑简化版 void BleTester::startConnection(const QBluetoothAddress addr) { if (m_controller) { m_controller-disconnectFromDevice(); // 强制清理旧状态 delete m_controller; } m_controller QLowEnergyController::createCentral(addr, this); connect(m_controller, QLowEnergyController::connected, this, [this]() { qDebug() BLE connected, starting service discovery...; m_state BleState::ServiceDiscovery; m_controller-discoverServices(); // 必须在此触发 }); connect(m_controller, QLowEnergyController::discoveryFinished, this, [this]() { if (m_state BleState::ServiceDiscovery) { auto services m_controller-services(); if (!services.isEmpty()) { m_service m_controller-createServiceObject(services.first(), this); connect(m_service, QLowEnergyService::stateChanged, this, BleTester::onServiceStateChanged); m_service-discoverDetails(); // 触发特征值发现 } } }); m_controller-connectToDevice(); // 启动连接 }提示connectToDevice()并不阻塞它只是向 BlueZ 发起连接请求。真正的连接完成由connected信号通知且此时设备可能尚未完成链路层同步。因此discoverServices()必须在connected信号后调用而非connectToDevice()后立即调用——这是新手最常翻车的第一步。2.2 特征值发现解析 GATT 数据库结构与权限校验BLE 设备的 GATT 数据库是树状结构Service → Characteristic → Descriptor。QLowEnergyService::discoverDetails()会获取该服务下所有特征值及其描述符如 Client Characteristic Configuration DescriptorCCCD但不会自动解析权限位。例程中通过QLowEnergyCharacteristic.properties()提取原始属性标志并做语义化转换// 解析特征值权限关键参数 QString propertyToString(QLowEnergyCharacteristic::PropertyTypes prop) { QStringList props; if (prop QLowEnergyCharacteristic::Read) props Read; if (prop QLowEnergyCharacteristic::Write) props Write; if (prop QLowEnergyCharacteristic::WriteNoResponse) props WriteNoResp; if (prop QLowEnergyCharacteristic::Notify) props Notify; if (prop QLowEnergyCharacteristic::Indicate) props Indicate; return props.join(|); } // 在 characteristicDiscovered 信号中使用 void BleTester::onCharacteristicDiscovered(const QLowEnergyCharacteristic ch) { qDebug() Found char: ch.uuid().toString() Properties: propertyToString(ch.properties()) Value: ch.value().toHex(); // 关键校验若需写入必须确保 Write 或 WriteNoResponse 权限存在 if (m_targetWriteUuid ch.uuid()) { if (!(ch.properties() (QLowEnergyCharacteristic::Write | QLowEnergyCharacteristic::WriteNoResponse))) { qWarning() Target characteristic not writable!; emit writeFailed(Characteristic lacks write permission); return; } m_targetCharacteristic ch; } }参数说明QLowEnergyCharacteristic::WriteNoResponse对应 BLE 的 “Write Without Response” 操作无 ACK适合高频小数据如传感器配置Write则要求设备返回 ATT Write Response适合关键指令如固件升级触发。例程默认优先尝试WriteNoResponse降低功耗失败后自动降级为Write并记录重试次数。2.3 MTU 协商为什么你的 512 字节包总被截断BLE 默认 ATT MTU 为 23 字节1 字节 opcode 2 字节 handle 20 字节 value。若设备支持扩展 MTU如 247 字节必须显式协商。Qt 的QLowEnergyController::exchangeMtu()是异步操作且仅在连接建立后、服务发现前调用才有效BlueZ 限制// 正确时机connected 信号后、discoverServices() 前 connect(m_controller, QLowEnergyController::connected, this, [this]() { // 尝试协商最大 MTUBlueZ 通常支持 517但设备端可能限制 m_controller-exchangeMtu(517); }); connect(m_controller, QLowEnergyController::mtuChanged, this, [this](quint16 mtu) { qDebug() MTU negotiated: mtu; // 此时再调用 discoverServices() m_controller-discoverServices(); });血泪经验某次调试某传感器模块死活读不出 128 字节的校准数据。抓包发现 ATT Read Request 总是被切成 23 字节块设备端未实现长读Long Read流程。强行exchangeMtu(247)后单次read()成功返回完整数据——MTU 不是可选项是大 payload 通信的前提。3. 特征值读写实战同步阻塞 vs 异步信号何时该用哪种模式Qt BLE API 全部异步但业务逻辑常需“写完等回读”。例程提供两种模式封装纯信号驱动推荐和QEventLoop 阻塞等待仅调试用。前者符合 Qt 事件循环哲学后者易导致 UI 冻结但对快速验证逻辑极有用。3.1 异步读写基于信号的状态流转与超时保护真实场景中一次写操作可能因设备忙、信号弱、GATT 事务冲突而失败。例程为每次读写绑定独立超时定时器并在characteristicWritten()/characteristicRead()信号中清除// 写入特征值带超时 void BleTester::writeCharacteristic(const QLowEnergyCharacteristic ch, const QByteArray value, bool withResponse) { if (!m_service || m_service-state() ! QLowEnergyService::ServiceDiscovered) { emit writeFailed(Service not ready); return; } // 启动 5 秒超时BLE 典型事务窗口 m_writeTimer.start(5000); m_pendingWriteChar ch; if (withResponse) { m_service-writeCharacteristic(ch, value, QLowEnergyService::WriteWithResponse); } else { m_service-writeCharacteristic(ch, value, QLowEnergyService::WriteWithoutResponse); } } // 写入完成回调 void BleTester::onCharacteristicWritten(const QLowEnergyCharacteristic ch, const QByteArray value) { if (ch m_pendingWriteChar m_writeTimer.isActive()) { m_writeTimer.stop(); qDebug() Write success: ch.uuid().toString() value: value.toHex(); emit writeSuccess(ch, value); m_pendingWriteChar QLowEnergyCharacteristic(); // 清空待处理 } } // 超时处理 void BleTester::onWriteTimeout() { if (m_pendingWriteChar.isValid()) { qWarning() Write timeout for m_pendingWriteChar.uuid().toString(); emit writeFailed(Write timeout); m_pendingWriteChar QLowEnergyCharacteristic(); } }逻辑说明QLowEnergyService::writeCharacteristic()调用后立即返回不等待设备响应。characteristicWritten()信号在收到 ATT Write Responsewith response或本地发送完成without response时触发。注意WriteWithoutResponse模式下此信号仅代表主机已发出数据包不代表设备已处理——需配合 Notify/Indicate 机制确认设备状态。3.2 阻塞式读写仅调试QEventLoop 的安全用法调试时常需“写指令 → 立即读回执”。用QEventLoop可模拟同步但必须确保不嵌套在已有事件循环中如QMainWindow::show()后直接调用会死锁// 调试专用阻塞等待写入完成慎用 bool BleTester::writeBlocking(const QLowEnergyCharacteristic ch, const QByteArray value, int timeoutMs 5000) { QEventLoop loop; bool success false; QTimer timer; timer.setSingleShot(true); timer.connect(timer, QTimer::timeout, loop, QEventLoop::quit); connect(this, BleTester::writeSuccess, [](const QLowEnergyCharacteristic, const QByteArray) { success true; loop.quit(); }); connect(this, BleTester::writeFailed, [](const QString) { loop.quit(); }); writeCharacteristic(ch, value, true); // 强制 with response timer.start(timeoutMs); loop.exec(); // 阻塞直到信号或超时 timer.stop(); return success; }参数说明timeoutMs设为 5000ms 是经验值覆盖典型 BLE 连接间隔7.5ms~4s和设备处理延迟。生产环境严禁使用此模式UI 线程将完全冻结。3.3 批量读写与队列管理避免 GATT 事务洪水BLE 协议规定同一连接上不能并行多个 ATT 请求。若连续调用readCharacteristic()后继请求会被 BlueZ 缓存但若设备响应慢缓存溢出会导致OperationError。例程实现简易 FIFO 队列struct PendingRead { QLowEnergyCharacteristic ch; std::functionvoid(const QByteArray) callback; }; void BleTester::queueRead(const QLowEnergyCharacteristic ch, std::functionvoid(const QByteArray) cb) { m_readQueue.enqueue({ch, cb}); if (m_readQueue.size() 1) { // 队列空时启动 processNextRead(); } } void BleTester::processNextRead() { if (m_readQueue.isEmpty()) return; auto pending m_readQueue.dequeue(); m_service-readCharacteristic(pending.ch); // 发起读 // 绑定一次性回调用 lambda 捕获 pending connect(m_service, QLowEnergyService::characteristicRead, this, [this, pending](const QLowEnergyCharacteristic ch, const QByteArray value) { if (ch pending.ch) { pending.callback(value); // 执行用户回调 processNextRead(); // 处理下一个 } }, Qt::SingleShotConnection); }避坑点Qt::SingleShotConnection确保回调只执行一次避免信号多次触发导致队列错乱。processNextRead()在回调内递归调用保证串行。4. 避坑BLE 通信中五个必踩的“静默失败”现场BLE 开发最折磨人的不是报错而是无声无息的失败API 调用返回成功日志显示“done”但设备毫无反应。以下是该例程实测复现并解决的五大静默陷阱每一条都来自真实联调现场。4.1 现象QLowEnergyController::connectToDevice()返回 true但connected信号永不触发原因目标设备处于“不可连接”广播模式如只广播 ADV_IND 但未开启可连接标志或主机 BlueZ 服务异常bluetoothdcrash。Qt 的connectToDevice()仅向 BlueZ 发送请求不校验设备实际可连接性。解决用sudo btmon抓包观察是否出现LE Create Connection命令及后续Connection Complete事件若无Connection Complete检查设备广播包sudo hcitool lescan --duplicates看设备是否在列表中再sudo hcidump -X解析广播数据确认ADV_IND中Connectable位为 1重启 BlueZsudo systemctl restart bluetooth。4.2 现象QLowEnergyService::discoverDetails()完成但characteristicDiscovered()信号一个没来原因设备 GATT 数据库未正确声明特征值权限Properties 字段为 0或特征值句柄Handle超出 BlueZ 缓存范围常见于自定义服务中 handle 分配混乱。解决用nRF ConnectApp 连接同一设备确认其 GATT 结构正常在discoverDetails()后手动遍历QLowEnergyService::characteristics()获取所有特征值部分设备不发characteristicDiscovered信号但数据已加载检查设备端代码BLE_GATTS_CHAR_MD_t中char_props必须设置BLE_GATTS_CHAR_PROP_READ等对应位。4.3 现象writeCharacteristic()后characteristicWritten()触发但设备未执行动作原因写入类型不匹配。设备期望WriteWithResponse但代码用了WriteWithoutResponse或设备端未实现BLE_GATTS_EVT_WRITE事件处理。解决抓包确认 ATT 层btmon中搜索ATT: Write Requestwith response或ATT: Write Commandwithout response设备端添加日志在BLE_GATTS_EVT_WRITE回调中打印p_evt-params.write.handle和p_evt-params.write.len确认是否被调用例程中强制先试WriteWithResponse失败再切WriteWithoutResponse。4.4 现象读取特征值返回空QByteArray但characteristicRead()信号正常触发原因特征值权限为Read但设备端未在BLE_GATTS_EVT_READ事件中填充p_evt-params.read.p_data或填充长度为 0。解决设备端检查BLE_GATTS_EVT_READ处理函数确保p_evt-params.read.p_data指向有效缓冲区且p_evt-params.read.len设置正确Qt 端增加空值检测if (value.isEmpty()) { qWarning() Read returned empty value; }用nRF Connect手动读同一特征值交叉验证。4.5 现象QLowEnergyController::disconnectFromDevice()后设备仍显示“已连接”原因Qt 仅向 BlueZ 发送断开请求但 BlueZ 未真正关闭 ACL 链路常见于设备端未响应DisconnectLMP 包。解决调用disconnectFromDevice()后监听QLowEnergyController::disconnected信号而非依赖视觉判断强制清理sudo hcitool disconnect BD_ADDR设备端增加BLE_GAP_EVT_DISCONNECTED事件处理确保断开后重置 GATT 状态。5. 进阶技巧用 QLowEnergyDescriptor 实现 Notify 自动订阅与断连恢复BLE 中Notify服务端主动推送是传感器类设备的核心能力。但订阅 Notify 需写入 CCCD0x2902描述符且断连后需重新订阅——手动管理极易遗漏。该例程将 CCCD 操作封装为enableNotification()方法并利用QLowEnergyController::disconnected信号自动重连重订。5.1 CCCD 描述符定位与写入不止是“写 0x0001”CCCD 是标准描述符UUID 固定为0x2902但必须通过QLowEnergyCharacteristic::descriptors()查找而非硬编码 handle。不同设备 CCCD handle 不同QLowEnergyDescriptor findCccdDescriptor(const QLowEnergyCharacteristic ch) { for (const auto desc : ch.descriptors()) { if (desc.uuid() QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) { return desc; } } return QLowEnergyDescriptor(); // Not found } void BleTester::enableNotification(const QLowEnergyCharacteristic ch) { auto cccd findCccdDescriptor(ch); if (!cccd.isValid()) { qWarning() CCCD descriptor not found for ch.uuid().toString(); return; } // 写入 0x0001 启用 Notify0x0002 为 Indicate QByteArray value; value.append(static_castchar(0x01)); value.append(static_castchar(0x00)); m_service-writeDescriptor(cccd, value); }参数说明CCCD 值为小端序0x0001Notify Enable0x0002Indicate Enable0x0000Disable。QLowEnergyService::writeDescriptor()同样需处理descriptorWritten()信号确认。5.2 断连自动恢复状态持久化与重连后重订Notify 订阅状态不随连接持久化。例程在disconnected信号中保存“已启用 Notify 的特征值列表”并在重连后自动重订// 成员变量 QSetQLowEnergyCharacteristic m_notifiedCharacteristics; // 启用 Notify 时记录 void BleTester::enableNotification(const QLowEnergyCharacteristic ch) { auto cccd findCccdDescriptor(ch); if (cccd.isValid()) { m_notifiedCharacteristics.insert(ch); // ... 写入 CCCD } } // 断连时清空可选也可保留重连后统一处理 void BleTester::onDisconnected() { m_notifiedCharacteristics.clear(); } // 重连后服务发现完成时重订 void BleTester::onServiceStateChanged(QLowEnergyService::ServiceState state) { if (state QLowEnergyService::ServiceDiscovered) { // 遍历当前服务所有特征值匹配已订阅的 for (const auto ch : m_service-characteristics()) { if (m_notifiedCharacteristics.contains(ch)) { enableNotification(ch); } } } }5.3 Notify 数据接收处理分包与粘包BLE Notify 数据长度受 MTU 限制。若设备发送 MTU 的数据会自动分包Fragmentation。Qt 的characteristicChanged()信号每次只传一包应用层需自行拼接// 成员变量 QMapQLowEnergyCharacteristic, QByteArray m_notifyBuffers; void BleTester::onCharacteristicChanged(const QLowEnergyCharacteristic ch, const QByteArray value) { // 对于大包设备可能分多次 Notify需设备端支持 Long Write 或分片协议 // 此处假设设备按固定帧头0xAA标识新包 if (value.length() 0 value[0] 0xAA) { // 新数据包清空缓冲区 m_notifyBuffers[ch].clear(); } m_notifyBuffers[ch].append(value); // 简单帧尾判断0x55——实际项目需按设备协议解析 if (!m_notifyBuffers[ch].isEmpty() m_notifyBuffers[ch].last() 0x55) { QByteArray completeFrame m_notifyBuffers[ch]; m_notifyBuffers[ch].clear(); emit notifyReceived(ch, completeFrame); } }表格Notify 关键参数与设备端配合要点参数Qt 端操作设备端要求验证方法CCCD 写入writeDescriptor(cccd, 0x0100)必须实现BLE_GATTS_EVT_WRITE处理 CCCDnRF Connect查看 CCCD 值Notify 触发监听characteristicChanged()调用sd_ble_gatts_hvx()发送btmon抓包ATT: Handle Value Notification数据分包应用层缓冲拼接设备端按 MTU 切分加帧头/尾抓包看多个 Notify 包断连恢复重连后writeDescriptor()重订无需特殊处理CCCD 状态不保留重连后nRF Connect查 CCCD 是否为 0从那以后我每次调试 BLE 通信第一件事就是打开btmon抓包第二件事是用nRF Connect交叉验证——Qt 的封装再好也绕不开协议层真相。这份例程的价值不在代码多炫而在把每个qDebug()日志背后的真实字节流、每个信号触发的协议事件、每个“成功”返回背后的硬件状态都钉死在可验证的坐标上。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

AP-0316语音处理模组实战:回声消除与波束成形调试指南

AP-0316语音处理模组实战:回声消除与波束成形调试指南

1. 这块模组到底解决了什么问题语音交互这件事,看起来简单,做起来处处是坑。你对着设备喊一句话,设备听到的可能是:你自己的声音、隔壁房间的电视声、空调出风口的呼呼声、桌面共振的低频嗡嗡声,以及电路本身产生的底噪…

2026/10/15 16:27:40 阅读更多 →
高光谱数据加载:PyTorch自定义Dataset与DataLoader全链路解析

高光谱数据加载:PyTorch自定义Dataset与DataLoader全链路解析

简介:面向PyTorch深度学习中需要处理高光谱图像的开发者,这份资源提供了一套完整的高光谱数据加载方案。方案基于DataLoader组件,详细说明了自定义Dataset类的编写方法、光谱通道的归一化处理、批大小的合理设置、多线程加载加速、随机打乱数…

2026/10/15 16:27:40 阅读更多 →
Texture2D.ReadPixels截屏原理与实战:从帧缓冲到图片文件

Texture2D.ReadPixels截屏原理与实战:从帧缓冲到图片文件

1. 截屏这件事,为什么值得单独拎出来聊做游戏开发或者图形工具开发的朋友,迟早会碰到一个需求:把当前画面截下来。可能是给玩家做个拍照模式,可能是自动化测试里要对比渲染结果,也可能是编辑器工具里要生成一张缩略图。…

2026/10/15 16:27:40 阅读更多 →

最新新闻

HospitalRun 前端项目演进全解:从 CHANGELOG 读懂 2.0 架构、破坏性变更与工程实践

HospitalRun 前端项目演进全解:从 CHANGELOG 读懂 2.0 架构、破坏性变更与工程实践

前端企业应用 【免费下载链接】hospitalrun-frontend Frontend for HospitalRun 项目地址: https://gitcode.com/gh_mirrors/ho/hospitalrun-frontend 点击查看 免费下载 本文以 HospitalRun 前端仓库(hospitalrun/frontend,当前版本 2.0.0-…

2026/10/15 17:15:25 阅读更多 →
LLC谐振参数计算实例:Mathcad工作表实现与增益曲线绘制

LLC谐振参数计算实例:Mathcad工作表实现与增益曲线绘制

简介:这份资源面向电力电子工程师与开关电源设计学习者,提供基于Mathcad的LLC谐振转换器参数计算实例,帮助解决谐振频率、变压器匝比、谐振电容电感等关键参数的计算与验证问题。压缩包共5个文件,包含3张jpg图片、1个txt文本和1个…

2026/10/15 17:15:25 阅读更多 →
安装包已更新,用户为什么还会下载到旧版本?

安装包已更新,用户为什么还会下载到旧版本?

创作说明:本文由 AI 辅助整理,协议说明参考 MDN。文中的路径和版本号均为假设示例,不代表某个生产站点的配置或测试结果。 假设一个站点始终使用 /download/current.exe,发布时直接替换这个路径对应的文件。服务器目录里已经是新…

2026/10/15 17:15:25 阅读更多 →
树莓派3B驱动0.96寸OLED:SSD1306的I2C初始化、显存与排障

树莓派3B驱动0.96寸OLED:SSD1306的I2C初始化、显存与排障

简介:面向树莓派3B玩家及嵌入式初学者,压缩包内是基于WiringPi库的0.96寸OLED(I2C接口)驱动示例工程,解决了在树莓派上快速点亮并控制OLED屏幕的常见需求。资源共10个文件,以C源码为主,包含oled…

2026/10/15 17:15:25 阅读更多 →
手写前端轻量监控工具rea:用过程数据回放排查线上性能问题

手写前端轻量监控工具rea:用过程数据回放排查线上性能问题

1. 为什么我会自己动手写 rea 这个工具1.1 一次线上事故把我逼到了墙角事情是这样的。半年前我做的一个前端项目在发版后的第三天,线上陆续出现首页白屏、按钮点了没反应、接口偶发超时报错的反馈。奇怪的是,我在本地开发环境里怎么折腾都复现不出来&…

2026/10/15 17:15:25 阅读更多 →
ASP.NET 实现 QQ 在线客服:可配置、权重轮询与移动端适配方案

ASP.NET 实现 QQ 在线客服:可配置、权重轮询与移动端适配方案

简介:这份资源面向具备一定C#与Web开发基础的ASP.NET学习者,围绕“QQ在线客服”这一典型场景,提供一套可参考的实现代码与配套素材,帮助理解如何将第三方开放平台能力嵌入自有网站。压缩包共14个文件,约117KB&#xff…

2026/10/15 17:14:23 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →