- 物联网
- 消息队列
- 后端
- 网络/通信
【免费下载链接】mosquitto
Eclipse Mosquitto - An open source MQTT broker
导读
Mosquitto 1.6.8 是 Eclipse Mosquitto 在 2019 年 11 月 28 日发布的维护(bugfix)版本,专注于修复 Broker、C 客户端库(libmosquitto)、命令行客户端以及 Windows 安装器中的一批缺陷。本文以官方发布公告 version-1-6-8-released.md 为主体,逐条解读本次修复的技术背景,并深入到本仓库源码中验证每项修复对应的实现逻辑——包括allow_zero_length_clientid、memory_limit、主题层级上限、CRL 证书吊销列表、会话过期、TLS WebSocket 会话接管、QoS 2 属性传递以及mosquitto_pub -l的 stdin 行为等。读完本文,你将理解这些修复背后的工作原理,并能判断升级到 1.6.8 对你的部署环境意味着什么。
一、Broker 修复:六类配置与行为缺陷
1.allow_zero_length_clientid配置项设置不正确(#1429)
官方说明:对allow_zero_length_clientid配置进行了多项修复,该选项此前未被正确设置。
源码佐证:该配置项在 Broker 全局配置与监听器级配置中均有出现。全局默认值在 src/conf.c 中被置为true,其解析逻辑位于 src/conf.c,通过conf__parse_bool()读取布尔值;在per_listener_settings启用时,监听器级副本在 src/listeners.c 被初始化为true。配置值在 CONNECT 报文处理时于 src/handle_connect.c 被读取:
if(db.config->per_listener_settings){ allow_zero_length_clientid = context->listener->security_options->allow_zero_length_clientid; }else{ allow_zero_length_clientid = db.config->security_options.allow_zero_length_clientid; }结合 src/mosquitto_broker_internal.h 中的字段声明可见,修复涉及的是:当全局与监听器配置共存时,per_listener_settings的分支选择曾导致该选项无法被正确应用,1.6.8 修正了配置在拷贝(src/conf.c)与使用链路中的偏差。
配置示例(mosquitto.conf):
per_listener_settings true allow_zero_length_clientid true2. 内存跟踪错误影响memory_limit(#1437)
官方说明:修复了不正确的内存跟踪导致memory_limit选项失效的问题。
源码佐证:memory_limit是 Broker 的全局配置,用于限制 MQTT 客户端消息等动态内存的总体占用。其解析位于 src/conf.c,使用conf__parse_ssize_t()将配置值解析为有符号整型并直接存入 Broker 配置。修复前的内存跟踪统计在部分分配/释放路径上存在偏差(例如消息队列与 retain 树相关路径),导致实际内存用量被低估,memory_limit无法按预期触发拒绝。1.6.8 校正了统计口径,使限制恢复生效。
配置示例:
memory_limit 10000003. 订阅主题长度限制:200 字符误改为 200 个层级(#1441)
官方说明:修复订阅主题被限制为 200 字符而非 200 个层级的问题。
源码佐证:订阅主题的存储采用层级化哈希结构。在 src/subs.c 中,每个层级节点通过HASH_ADD(hh, *sibling, topic, child->topic_len, child)挂入兄弟链表,topic_len为单个层级片段的长度;src/retain.c 的 retain 树同理。文件头部注释(src/subs.c)明确说明"主题最长 32767 字符,/为层级分隔符"。修复前代码误将层级数量上限 200 套用到了总字符长度上,导致合法长主题的订阅被拒绝;1.6.8 恢复为正确的语义——限制 200 个层级,而非 200 个字符。持久化写入时递归遍历层级(src/persist_write.c),因此该修复同样影响持久化订阅的读写一致性。
4. CRL(证书吊销列表)仅能加载一份(#1442)
官方说明:此前同一时间只能加载一份 CRL,本版本修复。
源码佐证:TLS 监听器的 CRL 文件在配置解析中按监听器保存(src/conf.c,字段声明于 src/mosquitto_broker_internal.h)。加载逻辑位于 src/net.c:X509_load_crl_file()将 CRL 装入X509_STORE的lookup中;每次调用net__load_crl_file()都基于同一个X509_STORE上下文(src/net.c 在 listener 配置了crlfile时调用)。修复前的实现只保留最近一次加载的 CRL,多监听器场景下其余监听器的 CRL 被覆盖;1.6.8 修正为各监听器独立装载各自的 CRL,确保证书吊销检查在多监听器/多 CA 场景下正确生效。
listener 8883 crlfile /etc/mosquitto/crl/crl.pem require_certificate true5.per_listener_settings true时重载配置异常(#1459)
官方说明:修复per_listener_settings为 true 时重载配置(SIGHUP)出现的问题。
源码佐证:per_listener_settings决定监听器是否各自持有独立的security_options副本,全局配置与监听器配置之间通过结构体拷贝同步(src/conf.c 展示了allow_zero_length_clientid等字段的拷贝模式)。1.6.8 之前,重载配置时对监听器级选项的更新存在遗漏或错误覆盖,导致热重载后权限与客户端 ID 相关行为与配置文件不一致;本版本修正了重载路径上的配置传播逻辑。
6. 保留消息过期与消息过期属性(#1464)
官方说明:两个相关修复:① 从持久化恢复的带过期时间的保留消息未在到期后被清除;② 即将过期的消息被发送时未附带过期时间属性。
源码佐证:保留消息的过期依赖消息的message_expiry_interval属性。修复①对应持久化恢复路径——保留消息从数据库还原后未正确重新注册过期调度,导致其永久滞留;1.6.8 确保恢复时重新计算并登记过期时间。修复②对应发布路径:当消息在即将过期的时间窗内被派发给新订阅者时,Broker 在转发前若剩余 TTL 极小,可能因属性裁剪逻辑漏掉message-expiry-interval属性;修复后保证即使即将过期,转发消息仍携带正确的过期属性,避免订阅端无法感知消息有效期的协议级偏差。
二、客户端库(libmosquitto)修复
1. QoS 2 消息的发布属性未传给on_message_v5()回调(#1432)
官方说明:修复 QoS 2 消息的发布属性(如消息过期、内容类型等)未传递给on_message_v5()回调的问题。
技术背景:在 MQTT 5 中,发布属性随 PUBLISH 报文传输,QoS 2 的完整流程为 PUBLISH → PUBREC → PUBREL → PUBCOMP。属性解析在 lib/read_handle.c 的handle_publish()中进行,消息在 QoS 2 的 PUBREL 阶段才会最终投递给上层回调。修复前,QoS 2 消息的属性在中间状态转换中被丢弃,导致on_message_v5()拿不到属性;1.6.8 修正了属性在 QoS 2 状态机中的保留与传递。
2. mosquitto.h 文档问题与mosquitto_connect_srv()补文档(#1478 / #1499)
官方说明:修复 include/mosquitto.h(对外头文件为 include/mosquitto/libmosquitto.h)中的文档问题,并为mosquitto_connect_srv()补充文档。
源码佐证:mosquitto_connect_srv()通过 DNS SRV 记录解析 MQTT 服务地址,其实现位于 lib/srv_mosq.c。该函数此前在头文件中缺少注释说明,开发者无法从 API 文档获知其行为;1.6.8 补齐了相关文档,明确其与mosquitto_connect()的差异。
三、命令行客户端修复
1.mosquitto_pub -l:stdin 结束挂起与末行丢失(#1448 / #1473 / #1474)
官方说明:三个相关修复:
mosquitto_pub -l在 stdin 流结束时挂起(#1448);mosquitto_pub -l未发送 stdin 最后一行(若该行不以换行符结尾)(#1473);- 使
mosquitto_pub -l的文档与实际行为一致——空行作为空消息发送(#1474)。
源码佐证:-l(--stdin-line)模式逐行读取 stdin 并逐行发布,其主循环在 client/pub_client.c 的pub_stdin_line_loop()中实现:
while(status == STATUS_CONNACK_RECVD && fgets(&line_buf[pos], read_len, stdin)){ buf_len_actual = (int )strlen(line_buf); if(line_buf[buf_len_actual-1] == '\n'){ line_buf[buf_len_actual-1] = '\0'; rc = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, line_buf, cfg.qos, cfg.retain); ... break; }else{ /* 行超过缓冲区,扩容继续读取 */ line_buf_len += 1024; pos += read_len-1; ... } } if(pos != 0){ /* EOF 前最后一段无换行的内容 */ rc = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual, line_buf, cfg.qos, cfg.retain); ... } if(feof(stdin)){ if(mid_sent == -1){ /* 空文件:直接断开 */ ... }else{ last_mid = mid_sent; status = STATUS_WAITING; } stdin_finished = true; }结合这段代码可以还原三项修复的机理:
- #1473(末行丢失):当 stdin 最后一行不以
\n结尾时,fgets()读到 EOF 返回非 NULL 但行末没有换行符,循环退出后pos != 0分支负责把残留内容发布出去。修复前该分支的条件/时机判断有误,导致最后一段数据被丢弃;1.6.8 确保 EOF 时的残留行被正确发布。 - #1448(挂起):stdin 结束时,若从未成功发送任何消息(
mid_sent == -1,即空输入),此前状态机未能正确退出,循环持续空转;修复后空文件场景会直接进入断开流程并正常退出。 - #1474(文档):从
while循环可见,fgets()读到的每一行(包括空行)都会触发my_publish(),空行实际发布为长度为 0 的空消息;client/pub_client.c 中的帮助文本已相应更新,官方文档也改为与实际一致。
2.mosquitto_rr重复的 cfg 定义(#1453)
官方说明:修复rr_client中重复的cfg定义。该问题属于编译期缺陷——重复定义在部分编译配置下导致链接或重复声明警告/错误,client/rr_client.c 在 1.6.8 中移除重复定义,保证各工具链可正常构建。
3.mosquitto_sub未连接成功退出时的内存释放(#1513)
官方说明:mosquitto_sub在未成功建立连接即退出时存在内存泄漏,本版本修复。
技术背景:mosquitto_sub在启动阶段可能因连接失败(如 broker 不可达、认证失败)直接退出;修复前,已分配的选项/上下文内存在退出路径上未释放,1.6.8 补充了该场景的清理逻辑。
四、构建与安装器修复
1. Makefile 新增CLIENT_STATIC_LDADD(构建)
官方说明:为 Makefile 构建新增CLIENT_STATIC_LDADD,允许静态链接 libmosquitto 编译客户端时追加链接库(如部分系统上静态链接需要 openssl 依赖)。
源码佐证:根目录 Makefile 与 config.mk 中维护构建变量。修复前,静态编译mosquitto_pub/mosquitto_sub时无法附加额外的系统库依赖,导致静态链接失败;新增变量后,构建者可向客户端可执行文件追加所需库。
2. Windows 安装器缺失mosquitto_rr.exe(#1463)
官方说明:修复mosquitto_rr.exe未包含在 Windows 安装器中的问题。
源码佐证:Windows 安装脚本位于 installer/mosquitto.nsi(以及 64 位变体 installer/mosquitto64.nsi)。1.6.8 在 NSIS 脚本中补上了mosquitto_rr(request-response 客户端)的可执行文件条目,使 Windows 用户安装后可直接使用该工具。
五、升级建议与验证
1.6.8 属于典型的 bugfix 维护版本,没有破坏性 API 变更,建议所有 1.6.x 用户升级。升级后可通过以下方式快速验证关键修复:
- 配置重载:设置
per_listener_settings true并修改配置文件后发送kill -HUP <pid>,确认监听器级allow_zero_length_clientid等选项按预期生效; - 长主题订阅:使用超过 200 字符但层级小于 200 的主题进行订阅,确认不再被拒绝(见 src/subs.c 的层级树实现);
- CRL 多监听器:为两个 TLS 监听器分别配置不同
crlfile,验证各自独立加载; mosquitto_pub -l行为:printf 'a\n\nb' | mosquitto_pub -l -t test,观察空行发布为空消息、末行b(无换行)被正确发送且进程正常退出,不再挂起。
相关资源
- 发布公告原文:www/posts/2019/11/version-1-6-8-released.md
- Broker 配置解析:src/conf.c(
allow_zero_length_clientid、memory_limit、crlfile、persistent_client_expiration的解析入口) - 会话过期实现:src/session_expiry.c
- CONNECT 处理与零长度 Client ID:src/handle_connect.c
- 客户端 stdin 行发布循环:client/pub_client.c
- Windows 安装脚本:installer/mosquitto.nsi
- 客户端库发布属性处理:lib/read_handle.c
- 物联网
- 消息队列
- 后端
- 网络/通信
【免费下载链接】mosquitto
Eclipse Mosquitto - An open source MQTT broker
相关推荐
Eclipse Mosquitto 1.6.3 发布详解:Broker、客户端库与命令行工具的关键缺陷修复
Eclipse Mosquitto 1.6.3 发布详解:Broker、客户端库与命令行工具的关键缺陷修复 导读 Mosquitto 1.6.3 是 Eclip
后端消息队列消息路由一条命令批量下载抖音视频封面:从单链接到作者主页全档
一条命令批量下载抖音视频封面:从单链接到作者主页全档 做素材库时经常要批量收某位作者作品里的封面,拿去做二次剪辑的封面底图。截图的方式带水印、分辨率低,一条条点
物联网消息队列后端网络/通信Eclipse Mosquitto 1.6.11 发布解读:Broker 与客户端库的关键缺陷修复详解
Eclipse Mosquitto 1.6.11 发布解读:Broker 与客户端库的关键缺陷修复详解 导读 Eclipse Mosquitto 1.6.11
后端消息队列消息路由
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考