You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mosquitto跨协议消息投递异常:MQTT客户端无法向WebSocket客户端发消息

问题描述

在Windows系统运行Mosquitto,配置1883端口使用MQTT协议,9001端口使用WebSocket协议。预期MQTT客户端发布的消息能被WebSocket客户端接收,但实际无法实现。

  • MQTT客户端之间、WebSocket客户端之间均可正常收发消息,但跨协议消息无法投递
  • 使用-v参数启动Mosquitto后,日志仅记录WebSocket客户端的连接与消息操作,不记录MQTT客户端的相关行为,但MQTT客户端侧显示连接和发布操作均正常(使用MQTTNet客户端以MQTT/WebSocket模式发布消息,PAHO JavaScript客户端以WebSocket模式订阅/接收消息)
  • 开启或关闭防火墙均未改变现状

配置文件片段

listener 1883
protocol mqtt
listener 9001
protocol websockets
password_file mypasswordfile.pwd

启动日志

prompt> ./mosquitto -c myconfig.conf -v
2022-10-15 20:25:53: mosquitto version 2.0.15 starting
2022-10-15 20:25:53: Config loaded from myconfig.conf.
2022-10-15 20:25:53: Opening ipv6 listen socket on port 1883.
2022-10-15 20:25:53: Opening ipv4 listen socket on port 1883.
2022-10-15 20:25:53: Opening websockets listen socket on port 9001.
2022-10-15 20:25:53: mosquitto version 2.0.15 running

发布端代码(MQTTNet)

var mqttFactory = new MqttFactory();
var mqttClient = mqttFactory.CreateMqttClient();
var mqttClientOptions = new MqttClientOptionsBuilder().
    // WithTcpServer("localhost").                     // 此方式无效
    WithWebSocketServer("ws://localhost:9001/mqtt").   // 此方式有效
    WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V311).
    WithClientId("publisher-client-id").
    WithCredentials("myusername", "mypassword").
    Build();
mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None).Wait();

var builder = new MqttApplicationMessageBuilder();
var applicationMessage = builder
    .WithTopic("mytopic")
    .WithPayload("mypayload")
    .Build();
mqttClient.PublishAsync(applicationMessage, CancellationToken.None).Wait();

订阅端代码(PAHO JavaScript)

mqttConnect() {
    this._mqtt = new Paho.MQTT.Client('localhost', 9001, '/mqtt', 'subscriber-client-id');
    this._mqtt.onConnectionLost = this.onMqttConnectionLost.bind(this);
    this._mqtt.onMessageArrived = this.onMqttMessageReceived.bind(this);
    const options = {
        mqttVersion: 4,
        userName: 'myusername',
        password: 'mypassword',
        onSuccess: this.onMqttConnected.bind(this),
        onFailure: this.onMqttFailedConnecting.bind(this)
    };
    this._mqtt.connect(options);
    ...
}
onMqttConnected() {
    console.log('Connected to MQTT broker');
    ...
    this._mqtt.subscribe('mytopic');
}
onMqttMessageReceived(message) {
    console.log('Received MQTT message; topic = ' + message.destinationName + ', payload = ' + message.payloadString);
    ...
}

问题分析与解决

这不是Mosquitto的功能限制,问题出在Mosquitto 2.x的默认安全配置以及MQTT客户端的连接有效性上:

1. Mosquitto 2.x的默认访问控制规则

Mosquitto 2.0及以上版本默认启用严格的访问控制策略,未显式配置时,不同listener(对应不同协议端口)的客户端默认处于隔离的访问域,无法跨域转发消息。同时,客户端仅能访问自身发布的主题内容。

解决步骤:

在配置文件中添加访问控制相关配置:

allow_anonymous false
acl_file myaclfile.acl

创建myaclfile.acl文件,添加规则允许指定用户访问目标主题:

user myusername
topic readwrite mytopic

如果是测试场景,可使用更宽松的规则(生产环境需严格限制):

pattern readwrite #

2. MQTT客户端连接有效性问题(日志无记录的原因)

你提到使用WithTcpServer("localhost")连接1883端口时,Mosquitto日志无记录,但客户端显示连接正常——这说明客户端并未真正完成MQTT握手,只是本地TCP连接成功,实际未接入Mosquitto。

排查与修复:

  • 确认MQTT客户端连接时指定了正确的端口(1883),且用户名密码与password_file中的内容匹配
  • 检查password_file是否通过mosquitto_passwd工具正确生成,确保myusername的密码哈希有效
  • 用mosquitto_pub工具直接测试MQTT协议发布:
mosquitto_pub -h localhost -p 1883 -u myusername -P mypassword -t mytopic -m "test payload"

如果此操作也无日志记录,需进一步排查:

  • 用netstat -ano | findstr :1883检查1883端口是否被其他进程占用
  • 将客户端连接地址改为127.0.0.1,避免localhost解析到IPv6地址导致的连接异常

3. 协议版本兼容性验证

订阅端PAHO客户端指定mqttVersion:4(对应MQTT 3.1.1),发布端MQTTNet也使用了V311版本,二者协议版本匹配,无需调整。

总结

核心问题是Mosquitto 2.x的默认ACL规则阻止了跨协议客户端的消息转发,添加正确的ACL配置后即可实现互通。同时需确保MQTT客户端真正成功连接到1883端口(可通过Mosquitto日志验证)。


内容的提问来源于stack exchange,提问作者Giorgio Barchiesi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:25:17