BCB6上云案例:用WinSock手写MQTT客户端实现物联网通信
简介面向需要在 Borland C Builder 6.0 中接入 MQTT 的 C 开发者这份案例基于 Eclipse Paho MQTT C 库演示了客户端创建、服务器连接、消息发布、主题订阅与断开连接等完整流程能够帮助理解发布/订阅模型和轻量级通信协议在 Windows 桌面程序中的实际落地。压缩包共 15 个文件大小仅 225KB包含主源码、DLL 动态库、配套 LIB 静态库与头文件并提供可执行程序、连接配置和工程文件基本覆盖从编译链接到运行配置所需的全部内容。目前已有 462 人学习下载。对于想快速在 BCB6 上跑通 MQTT 的入门者其中既提供可直接阅读的参考代码又附带已编译好的库和演示程序省去自行搭建 Paho 环境的繁琐过程同时可作为扩展物联网消息功能、制作小型客户端或课程设计的实用模板。案例中的主源码还给出了关键函数调用顺序配套目录便于直接配置工程对入门者尤其友好。1. 老 IDE 连新总线BCB6 的 MQTT 案例到底能解决什么问题我手上维护的上位机里BCB6 写出来的占了将近一半跑在现场工控机上串口、Modbus 逻辑都稳定唯一尴尬的是“上云”这一步。新平台的物联网接口基本只认 MQTT而 BCB6 没有官方 MQTT 组件网上搜到的教程又全是 C#、Python 的真正落在 C Builder 工程里的案例少得可怜。这套以 BCB6 为运行环境的 MQTT 案例核心目标就是让你不改原有架构只新增一个基于 WinSock 的 MQTT 客户端类就能把采集到的数据发布到 Broker也能订阅到云端下发的指令。它把 CONNECT、PUBLISH、SUBSCRIBE、心跳和断线重连都封装进几段可以编译的代码里适合正在维护老项目又被物联网协议卡住的工程师也适合想在 BCB6 里亲手摸一遍 MQTT 报文字节流的学习者。2. MQTT 协议选型在 BCB6 里手撸报文比引第三方库更实际2.1 第三方 MQTT 库进入 BCB6 前的现实成本很多刚接触这个组合的人第一反应是找一个现成的 MQTT 库引进来。我在一批案例里跑过这个路线最后基本都放弃。原因不是库不好是 BCB6 的落伍超出了多数库作者的预期。首先BCB6 编译器对 C98 的兼容是主流但现代 MQTT 库在写的时候默认你用的是新编译环境里面摞了 move 语义、lambda、模板泛型之类的东西。把源码拖进 BCB6 里编一遍屏幕上会冒出一堆模板报错。改这些错误消耗的时间足够自己把 MQTT 包的构造逻辑吃透。我在这类项目上的体会是给老 IDE 引新库往往是给自己挖坑。其次运行期依赖。部分库编译出来还需要额外的动态库部署到客户现场时那个文件夹里又会多出好几个 DLL。老现场的工控机上系统权限管得严允许装什么程序都有清单这种额外的安装动作经常被客户拒绝。纯静态、零依赖的方案在老产线里有天然的落地优势。最后从需求最小化的角度看MQTT 客户端最常用的报文其实就那么几种CONNECT、CONNACK、PUBLISH、SUBSCRIBE、SUBACK、PINGREQ、PINGRESP、DISCONNECT。这些报文格式在协议文档里写得清清楚楚手动填字节完全可以控制。选型时我通常先问一句是引一个库进来引入更多不确定因素还是把七八个报文的字节格式定义好自己写一个轻量类。答案在后者的项目占多数。所以这套案例里的做法就是不用第三方库直接基于 WinSock 实现一个 MQTT 客户端类类里包含 socket 句柄、收发缓冲区、报文解析状态机再加上连接、发布、订阅、心跳四个方法。这样既照顾了 BCB6 的编译环境也方便拿到现场直接改。2.2 需要认识的报文集合连接、发布、订阅、心跳MQTT 3.1.1 中每个报文的第一字节叫固定头高四位表示报文类型低四位是标志位。类型值从 1 到 14真正在案例里用到的我列了一张表报文类型类型值作用方向CONNECT1客户端发起登录请求客户端到 BrokerCONNACK2Broker 返回连接结果Broker 到客户端PUBLISH3发布应用消息双向SUBSCRIBE8订阅主题过滤器客户端到 BrokerSUBACK9确认订阅成功及授予的 QoSBroker 到客户端PINGREQ12心跳请求客户端到 BrokerPINGRESP13心跳响应Broker 到客户端DISCONNECT14客户端主动断开客户端到 Broker从这张表能看出典型的上云流程先发 CONNECT 完成握手收到 CONNACK 确认然后 SUBSCRIBE 等待云端下发指令周期发送 PINGREQ 保持链路数据采集后 PUBLISH 上报程序退出时 DISCONNECT。对做过串口和 Modbus 的工程师来说MQTT 最难适应的不是报文多而是所有数据都是字节流。没有结构体映射没有内存对齐要求你按协议规定顺序往缓冲区里填。这也是案例代码里大量使用 AnsiString 拼接的原因BCB6 对这种字符串操作支持得很顺。2.3 MQTT 包结构固定头、剩余长度和可变头的关系任何 MQTT 报文都由固定头、可变头、有效载荷组成。固定头里最核心的两个字段是报文类型和剩余长度。剩余长度指的是“当前字节之后到报文结束的所有字节数”不包含固定头本身采用连续编码每个字节的最高位表示是否还有下一个字节低 7 位表示实际值。报文长度小于 128 时一个字节够用超过 127 就要用两个字节。我习惯在代码里单独封装一个剩余长度编码函数因为后面构造 PUBLISH 长报文时会反复用到。案例里我把编码函数放在 MQTT 类的私有方法里每次发包前统一调用。这样做的坑在于接收入口也必须对剩余长度做边界检查。很多老代码直接在 recv 后用一个固定长度去解析收到大报文时缓冲区越界这是很典型的隐患。我一般在解析状态机里先读一个字节判断剩余长度要占几字节再决定后续 recv 多少次。提示如果你是从串口改造到 MQTT最值得先打通的是 QoS0 的收发链路等字节流方向确认了再考虑 QoS1 和 QoS2 的重试与去重。BCB6 这类老 VCL 工程稳定跑到 QoS0 已经能覆盖绝大多数温湿度、电量、开关状态上报场景。3. 从 TCP 到 CONNACK在 BCB6 里把第一个 MQTT 连接跑通3.1 初始化 WinSock 并建立 TCP 通道BCB6 自带 VCL 的 Socket 组件不过这套案例里我建议直接用 WinSock API。原因是 MQTT 对连接状态控制要求高需要自己设置收发超时而 VCL 组件的 OnRead、OnWrite 事件在老工程里处理起来绕。直接调用 WinSock代码量反而更少调试也更直观。建立连接的代码在案例中是这样写的// 案例代码初始化 WinSock 并连接 Broker // 参数hostIP 为 Broker 地址port 一般为 1883 bool TMqttClient::ConnectToBroker(AnsiString hostIP, int port) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) return false; FSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (FSocket INVALID_SOCKET) return false; SOCKADDR_IN addr; addr.sin_family AF_INET; addr.sin_port htons(port); addr.sin_addr.S_un.S_addr inet_addr(hostIP.c_str()); int ret connect(FSocket, (SOCKADDR*)addr, sizeof(addr)); if (ret SOCKET_ERROR) { closesocket(FSocket); FSocket INVALID_SOCKET; return false; } return true; }这段代码的逻辑依次是WSAStartup 初始化 Socket 环境创建 TCP 套接字填充 Broker 地址并发起 connect。我把 connect 做成同步调用因为案例需求简单同步方式错误处理最直观连不上就返回 false调用方弹一个提示即可。参数上注意两点hostIP 用了 inet_addr只支持点分十进制的 IP如果现场要填域名就必须先调用 gethostbyname 解析port 默认填 1883如果 Broker 开了 TLS 会变成 8883但 BCB6 老工程处理 TLS 还要引 OpenSSL 动态库我建议先在明文链路把功能跑通加密留作后续增强。注意connect 在同步模式下没有超时参数Broker 地址不可达时程序可能卡在 connect 上十几秒甚至更久。案例默认用阻塞模式但代码里预留了设置非阻塞模式的注释位置现场网络差的时候可以打开。3.2 构造 CONNECT 包把协议版本和 CleanSession 填对TCP 建好后发送的第一条报文必须是 CONNECT否则 Broker 会直接断开连接。CONNECT 的固定头是 0x10可变头里包含协议名 MQTT、协议级别、连接标志和 KeepAlive。案例里的构造代码如下// MQTT 3.1.1 协议级别为 4 // 案例代码构造并发送 CONNECT 包 bool TMqttClient::SendConnect(AnsiString clientId, int keepAlive) { AnsiString packet; int protocolNameLen 4; // MQTT int remainLen 2 protocolNameLen 1 1 2 2 clientId.Length(); packet (char)0x10; // 固定头CONNECT packet (char)remainLen; // 剩余长度 packet (char)0x00; packet (char)protocolNameLen; packet MQTT; // 协议名 packet (char)0x04; // 协议级别 MQTT 3.1.1 packet (char)0x02; // CleanSession1 packet (char)(keepAlive 8); // KeepAlive 高字节 packet (char)(keepAlive 0xFF); // KeepAlive 低字节 packet (char)0x00; packet (char)clientId.Length(); packet clientId; // 客户端 ID int sent send(FSocket, packet.c_str(), packet.Length(), 0); return (sent packet.Length()); }这段代码有三个易错点。第一剩余长度计算。我这里写的是 2协议名长度字段加 4协议名加 1协议级别加 1连接标志加 2KeepAlive加 2客户端 ID 长度字段加 clientId.Length()。如果只写 10 加 clientId.Length()最后的报文会少两字节Broker 解析长度不匹配就会不回 CONNACK。第二连接标志字节。0x02 表示 CleanSession1不使用遗嘱、用户名、密码。如果 Broker 要求认证需要把对应位拉高再在载荷中追加用户名和密码字段这部分我建议拆成单独的方法。第三KeepAlive 是两字节大端序代码里用移位和与运算拆开。很多新手直接把 60 填成一个字节Broker 解析出的保活时间会变成 0等于关闭保活机制。BCB6 的 AnsiString 拼接 char 型变量没有编码问题但移位时最好显式把 keepAlive 转成 unsigned char避免符号位干扰。3.3 接收 CONNACK状态机与超时处理CONNECT 发出去后不能立刻发布数据必须等 Broker 回 CONNACK。CONNACK 完整报文只有 4 字节0x20、剩余长度 2、连接确认标志、返回码。最简单的接收函数如下// 案例代码接收 CONNACK返回 0 表示连接成功 int TMqttClient::WaitConnack() { char buf[4]; // 设置 3 秒接收超时 DWORD timeout 3000; setsockopt(FSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)timeout, sizeof(timeout)); int n recv(FSocket, buf, 4, 0); if (n 4) return -1; // 超时或数据不完整 if ((buf[0] 0xF0) ! 0x20) return -2; // 收到非 CONNACK 报文 return buf[3]; // 返回码0 表示成功 }这段代码有个边界情况容易踩recv 返回的 n 不一定等于 4。TCP 是流协议数据可能分批到达也可能一次到达。如果 Broker 延迟大第一次 recv 只收到 2 字节程序把 n 4 当成错误返回就误判了。稳妥做法是把接收动作写成一个循环累计收满指定字节数再返回。案例源码里封装了一个 ReadBytes 方法内部循环处理粘包和半包后续解析 PUBLISH、SUBACK 也要复用。返回码的判断同样要仔细。buf[3] 等于 0 表示连接成功等于 1 表示协议版本不对等于 2 或 5 表示客户端标识、用户名或密码被拒绝。看到非零返回码时不要反复重连优先查 Broker 日志。通过模拟项目 X 联调时我遇到过返回码 5 的案例最后定位是用户名密码标志位置位了但载荷里没拼密码字段Broker 鉴权失败。注意把 SO_RCVTIMEO 设成 3000 毫秒后等待 CONNACK 期间界面会阻塞。简单案例可以接受一旦牵扯大量发布订阅接收逻辑就必须挪到独立线程里这部分在第四章详细展开。4. 发布和订阅都要跑通一个可收可发的完整循环4.1 PUBLISH 包QoS0 与 QoS1 的构造差异连接成功后发布消息是最常用的动作。PUBLISH 固定头类型值是 3QoS 不同低四位标志不同QoS0 是 0x30QoS1 是 0x32QoS2 是 0x34。这套案例把 QoS0 作为默认因为大多数传感器上报场景允许丢一两条数据QoS0 的包结构最简单也不用管消息标识符。// 案例代码发布一条 QoS0 消息 bool TMqttClient::PublishQos0(AnsiString topic, AnsiString payload) { AnsiString packet; int payloadLen payload.Length(); int topicLen topic.Length(); int remainLen 2 topicLen payloadLen; packet (char)0x30; // 固定头QoS0 PUBLISH packet (char)remainLen; packet (char)0x00; packet (char)topicLen; // 主题长度 packet topic; // 主题 packet payload; // 载荷 return send(FSocket, packet.c_str(), packet.Length(), 0) packet.Length(); }发布包的剩余长度比 CONNECT 清晰主题长度字段占 2 字节主题 topicLen 字节载荷 payloadLen 字节。这里提醒一个老项目常见问题如果载荷里含中文字符AnsiString 在 BCB6 里的默认编码是 ANSI直接拼接没问题但订阅方拿到字节在 UTF-8 环境下会显示成乱码。实际项目里我会在采集时把中文字段先转成 UTF-8 再发布。升级到 QoS1 时固定头改成 0x32主题和载荷之间插入一个 2 字节消息标识符Broker 收到后会回 PUBACK类型值是 4。客户端必须等到 PUBACK 才能重发或继续这就需要在接收线程里维护一张“已发送未确认消息表”复杂度上一个台阶。所以案例先以 QoS0 为主链路完全稳定后再考虑升级。4.2 SUBSCRIBE 包订阅主题的正确姿势订阅报文的固定头是 0x82。这个字节很容易让新手误解低四位 0x02 不是 QoS2而是协议规定的 SUBSCRIBE 固定标志必须等于 0x02。案例里的订阅方法实现// 案例代码订阅一个主题过滤器 bool TMqttClient::Subscribe(AnsiString topicFilter) { AnsiString packet; int remainLen 2 2 topicFilter.Length() 1; packet (char)0x82; // SUBSCRIBE packet (char)remainLen; packet (char)0x00; packet (char)0x01; // 消息标识符1 packet (char)0x00; packet (char)topicFilter.Length(); packet topicFilter; packet (char)0x00; // 请求 QoS0 return send(FSocket, packet.c_str(), packet.Length(), 0) packet.Length(); }消息标识符不能在同一连接上重复使用每发一个 SUBSCRIBE 要递增。案例里硬编码为 1如果订阅多个主题需要把它改成成员变量每次加一。订阅之后Broker 会回 SUBACK固定头 0x90剩余长度 3包含消息标识符 2 字节和返回码 1 字节。返回码 0x00 表示订阅成功且授予的 QoS 是 00x80 表示订阅失败。处理 SUBACK 的逻辑和 CONNACK 一样在接收循环里按状态机解析。协议对 SUBSCRIBE 固定头有硬性要求写成 0x80 会被 Broker 视为协议违规直接断连。我给某跨平台系统接 MQTT 时遇到过这种问题发送端看起来一切正常Broker 日志里只有一条连接关闭记录。用抓包工具对比字节流才发现问题出在固定头低四位。4.3 心跳与重连KeepAlive 的良心参数选择MQTT 的 KeepAlive 是连接参数客户端在空闲时必须按这个时间间隔发出 PINGREQ否则 Broker 会认为链路失效并断开。PINGREQ 固定头是 0xC0剩余长度 0只有两字节也是 MQTT 里最简短的报文// 案例代码发送 PINGREQ 心跳 void TMqttClient::SendPing() { char pingReq[2] { (char)0xC0, 0x00 }; send(FSocket, pingReq, 2, 0); }Broker 收到后无条件回一个 PINGRESP固定头 0xD0同样两字节。KeepAlive 的值在 CONNECT 包里已经协商案例默认 60 秒。实际项目里如果现场网络不稳定或中间有 NAT 网关我会把 KeepAlive 缩短到 20 到 30 秒。因为 NAT 会话表有老化时间KeepAlive 比它长时连接会被网关悄然切断客户端还不知道直到下次发送数据才发现 Socket 已失效。重连逻辑上我建议“断开重试加固定间隔”的组合。重连前先关闭旧 Socket等待两秒再重新走 TCP 连接和 CONNECT 流程。MQTT 服务器在相同 ClientID 重连时可能会顶掉旧连接也可能拒绝新连接这取决于 Broker 实现。案例里我做了一个简单的重连函数// 断线重连重连成功后恢复订阅 void TMqttClient::Reconnect() { CloseSocket(); Sleep(2000); ConnectToBroker(FHost, FPort); if (SendConnect(FClientId, FKeepAlive) WaitConnack() 0) ResubscribeAll(); }ResubscribeAll 会把之前订阅过的主题再走一遍 SUBSCRIBE。这个动作不能省因为 Broker 在连接断开后会清除旧的订阅关系。4.4 消息分发把收到的报文塞回 VCL 界面BCB6 的 VCL 是单向线程模型界面必须在主线程操作。MQTT 接收线程如果直接改 Edit 的 Text 属性轻则闪烁重则崩溃。案例里的做法是用 PostMessage 把收到的完整报文投递给主窗口句柄// 接收线程核心逻辑简化展示 TMemoryStream* stream new TMemoryStream; // 从 Socket 读到 stream交给主线程处理 PostMessage(FMainFormHandle, WM_MQTT_DATA, (WPARAM)stream, (LPARAM)0);主窗口在处理 WM_MQTT_DATA 时再去解析 PUBLISH 报文取出主题和载荷更新界面。这个方案的关键点是 PostMessage 异步不会阻塞接收线程但流对象要在主线程用完后释放不能在线程里 delete。如果不喜欢 PostMessage也可以用 TThread.Synchronize但它会阻塞接收线程直到主线程执行完回调数据量大时容易丢包。我在案例里最后选用了 PostMessage这套机制在 BCB6 老工程中抗压能力最强。5. 避坑排查连接超时、收不到回包和界面卡死的五个现场5.1 现象CONNACK 迟迟不来抓包却看到 CONNECT 包已经发出调试现场Broker 地址填的是域名客户端解析没问题TCP 也连上了但 CONNACK 就是不回来。抓包看 CONNECT 包已经出现在网络上Broker 日志也没有异常报错。原因多半是 CONNECT 包里的协议名字段写成了 MQIsdp。这是 MQTT 3.1 的协议名老系统偶尔会混用Broker 如果只支持 3.1.1收到 MQIsdp 会不认。解决方法是统一把协议名写成 MQTT协议级别字节填 0x04同时检查客户端 ID 是否为空MQTT 3.1.1 不允许空客户端 ID。5.2 现象SUBACK 收不到Broker 忽然断开订阅消息发出去后程序一直等 SUBACK等了几秒 Socket 变成断开状态。我排查过一次是 SUBSCRIBE 报文的固定头低四位被写成了 0x00也就是把 0x82 写成了 0x80。协议规定 SUBSCRIBE 的固定标志位必须是 0b0010Broker 看到标志非法就会关闭连接。解决方法是严格按协议写 0x82发送后记录一条十六进制日志把固定头原始字节打印出来一眼就能定位。5.3 现象客户端能收数据但界面卡死或闪烁Socket 接收线程每收到一条 PUBLISH 就直接调用 Form 里的 Edit 组件赋值运行几分钟后界面失去响应。原因很明确VCL 组件必须在主线程操作接收线程直接改组件属性违反了线程模型造成界面句柄竞争最终卡死。解决方式就是第四章的 PostMessage 分发把数据投递到主窗口主线程处理函数里再做界面更新。这个改法耗时不多但能根治闪烁和卡死问题。5.4 现象发布 QoS1 消息后 Broker 立即断开连接QoS0 发布一切正常改成 QoS1 后消息发出去不到一秒Broker 就把 TCP 连接关了。原因是 QoS1 的 PUBLISH 包里缺少消息标识符字段。固定头改成了 0x32但剩余长度和实际内容还是 QoS0 的排列导致报文长度和内容对不上。解决办法是 QoS1 的剩余长度里必须加上 2 字节消息标识符并且发出后等待 PUBACK。如果没做 PUBACK 处理还不如继续用 QoS0。5.5 现象重连后旧连接没释放新连接被拒绝客户端断线后立刻重连Broker 没有把旧连接踢掉新连接的 CONNACK 返回一个非 0 值。原因是旧连接处于半开状态服务器端没有完全释放部分 Broker 的清理策略保守会先拒绝相同 ClientID 的新连接。解决办法是重连前主动关闭旧 Socket 并等待两秒让 Broker 完成旧连接清理或者重连时临时换用不同 ClientID。案例源码里选用前者对上层业务更透明。6. 验证与收尾用本地 Broker 日志确认链路再改造成自己的协议调试 MQTT 客户端建议做法是在本机跑一个测试 Broker把日志级别调到调试模式然后逐条对收发记录里的字节流。这样环境隔离出问题时基本可以确定是协议层的错误而不是设备或网络干扰。验证样例时我一般分两步走。第一步用命令行测试工具订阅一个验证主题比如 test/verify然后在 BCB6 样例里向这个主题发布一串固定字符。观察测试工具能不能收到。能收到说明 PUBLISH 方向已经通。第二步反向操作在测试工具里发布一条指令观察 BCB6 样例的接收线程是否触发回调。两边都能对上基础链路就没有问题。抓包验证只用看两个点一是 CONNECT 包的协议名和协议级别字节二是 SUBSCRIBE 和 PUBLISH 的固定头低四位。这两个点做二进制对比就行不需要理解深层实现。如果 Broker 日志和抓包都能对上MQTT 链路基本可以被认定为正确。我还会把 KeepAlive 临时改成 20 秒让客户端在空闲时多发几组 PINGREQ 和 PINGRESP观察日志里是否成对出现。如果心跳没成对说明网络中间有设备在过滤数据包。按我手上的经验从 BCB6 上车 MQTT最难的不是协议本身而是你愿不愿意按老工程的节奏把每个字节都写清楚。想走捷径引库的人最后大多绕回来自己拼包。因此拿到这类案例后我会先跑一遍上述验证路径然后把 CONNECT 和 SUBSCRIBE 两个包的长度校验单独提出来发送前用断言检查。从那以后我每次在 BCB6 里改 MQTT 都会强制走这个流程希望帮到你。本文还有配套的精品资源点击获取

相关新闻

数据采集作业源码全解析:爬虫、Flask模板与工程化改造

数据采集作业源码全解析:爬虫、Flask模板与工程化改造

简介:针对数据科学与大数据技术课程的数据采集作业设计源码,面向高校学生及课程教师,用于支撑数据采集模块的实践教学与课后练习。压缩包共69个文件,约38.08MB,包含28个PNG、20个JPG、9个HTML、8个Python脚本及少量说明…

2026/10/18 9:23:28 阅读更多 →
AI论文工具全攻略:从选题到定稿的10款实用软件

AI论文工具全攻略:从选题到定稿的10款实用软件

本科毕业那年,我最后两个月基本没怎么睡过整觉。白天蹲图书馆翻文献,晚上对着Word里空荡荡的页面发呆,格式调了一整夜第二天打开还是乱的。最崩溃的是辛辛苦苦写完的初稿,导师一句"研究背景写得太浅",我又从…

2026/10/18 9:23:28 阅读更多 →
AI基建转向Rust:推理引擎、边缘部署与算子库的工程实践

AI基建转向Rust:推理引擎、边缘部署与算子库的工程实践

1. 为什么“AI基建转向Rust”这个说法值得认真对待过去几年,但凡聊到AI基础设施,默认的技术栈几乎清一色是Python打底、C兜底、CUDA做加速。训练框架用Python写调度逻辑,算子用CUDA C写,推理引擎再用C封装一层。这套组合拳打了快十…

2026/10/18 9:22:28 阅读更多 →

最新新闻

推荐一个适合学习AI Agent开发的AI智能体开源项目:用TaoToken统一Key跑通DeepAgent实战

推荐一个适合学习AI Agent开发的AI智能体开源项目:用TaoToken统一Key跑通DeepAgent实战

/* 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 23:07:17 阅读更多 →
4步部署i茅台自动预约系统campus-imaotai:新手友好的实操指南

4步部署i茅台自动预约系统campus-imaotai:新手友好的实操指南

4步部署i茅台自动预约系统campus-imaotai:新手友好的实操指南 【免费下载链接】campus-imaotai i茅台app自动预约,每日自动预约,支持docker一键部署(本项目不提供成品,使用的是已淘汰的算法) 项目地址: h…

2026/10/18 23:07:17 阅读更多 →
FlyEnv 本地开发环境与 AI 协同能力深度评测:从 MCP 配置到 TaoToken 统一 Key 的落地实践

FlyEnv 本地开发环境与 AI 协同能力深度评测:从 MCP 配置到 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/18 23:07:17 阅读更多 →
什么是联邦学习?用 TaoToken 统一 Key 跑通横向联邦 MNIST 实验

什么是联邦学习?用 TaoToken 统一 Key 跑通横向联邦 MNIST 实验

/* 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 23:07:17 阅读更多 →
170、Agent技术社区与开源项目

170、Agent技术社区与开源项目

170、Agent技术社区与开源项目 昨天半夜在排查一个LangGraph的状态流问题,顺手翻了翻GitHub上一个Agent项目的issue区,看到一个老哥把messages列表在节点里直接append了,结果整个对话历史在并行分支里串了线。这种问题放在传统编程里就是共享可变状态,但放在Agent的图编排…

2026/10/18 23:07:17 阅读更多 →
SpringBoot+Thymeleaf实战:快速构建用户管理CRUD系统

SpringBoot+Thymeleaf实战:快速构建用户管理CRUD系统

写这段代码的时候,我特意用一个最朴素的后台管理页面做载体:用户信息管理。数据库一张表,页面三张,接口四种。线上跑通之后,我才觉得这套经典组合确实值得展开聊聊。SpringBoot负责把所有配置吞掉,Thymelea…

2026/10/18 23:06:16 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

2026/10/18 0:00:55 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →