PHP-MQTT发布端导致订阅端崩溃问题求助
MQTT订阅端因PHP-MQTT发布消息崩溃的问题排查
环境配置
Docker部署的Mosquitto服务配置
ecosystem: image: eclipse-mosquitto:latest ports: - '1883:1883' volumes: - ./mosquitto/config:/mosquitto/config - ./mosquitto/data:/mosquitto/data - ./mosquitto/log:/mosquitto/log networks: [ default, odinn_network ] restart: unless-stopped
Mosquitto核心配置(mosquitto.conf)
allow_anonymous true listener 1883
PHP-MQTT订阅端代码(Tinker环境运行)
use PhpMqtt\Client\MqttClient; $mqtt = new MqttClient('localhost', 1883, 'test'); $mqtt->connect(); $mqtt->subscribe('events/#', function ($topic, $message) { fwrite(STDERR, sprintf("topic = %s / message = %s\n", $topic, $message)); }); $mqtt->loop(true);
测试步骤与问题现象
步骤1:使用
mosquitto_pubCLI工具发布消息,执行命令:mosquitto_pub -h localhost -p 1883 -t events/123456 -m test订阅端正常输出:
topic = events/123456 / message = test2,符合预期。步骤2:使用PHP-MQTT客户端发布消息,代码如下:
use PhpMqtt\Client\MqttClient; $mqtt = new MqttClient('localhost', 1883, 'test'); $mqtt->connect(); $mqtt->publish('events/123456', 'test');此时订阅端循环直接崩溃,抛出错误:
PhpMqtt\Client\Exceptions\DataTransferException [65] Transferring data over socket failed: Sending data over the socket failed. Has it been closed?
问题分析
异常套接字说明
出问题的是订阅端与Mosquitto Broker之间的TCP套接字。
根因
核心问题是客户端ID冲突:订阅端和发布端使用了完全相同的客户端ID test。
根据MQTT协议规范,同一个客户端ID在Broker中只能存在一个活跃连接。当PHP-MQTT发布端以testID连接Broker时,Broker会立即强制断开之前已建立连接的、使用相同ID的订阅端。此时订阅端的loop()循环仍在尝试通过已被Broker关闭的套接字发送心跳包(PINGREQ)或处理后续数据,自然会触发套接字发送失败的异常。
修复方案
为发布端指定一个与订阅端不同的客户端ID即可解决问题,修改后的发布端代码示例:
use PhpMqtt\Client\MqttClient; // 更换客户端ID为test_publisher,避免与订阅端冲突 $mqtt = new MqttClient('localhost', 1883, 'test_publisher'); $mqtt->connect(); $mqtt->publish('events/123456', 'test');
内容的提问来源于stack exchange,提问作者vbulash
相关产品推荐
相关产品推荐

