webman mqtt报错

allen2910

问题描述

根据观法提供的workerman官方客户端在webman中执行命令:composer require workerman/mqtt

然后执行执行客户端接收mqtt消息是可以的,
但是后面开始编写业务的时候,如下面代码:

Log::info($topic);
Log::info($content);

就会报错:

TypeError: Argument 1 passed to support\Log::handlers() must be of the type array, null given, called in D:\develop\php\webman_admin\vendor\workerman\webman-framework\src\support\Log.php
 on line 55 and defined in D:\develop\php\webman_admin\vendor\workerman\webman-framework\src\support\Log.php:67

下面是完整代码:
启动代码:

declare(strict_types=1);
use Workerman\Worker;
use \app\mqttService\MqttService;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker();
$worker->onWorkerStart = function(){
    $options = [
        'username' => 'admin',
        'password' => '123456',
    ];
    $mqtt = new Workerman\Mqtt\Client('mqtt://192.168.1.5:1883',$options);

    $mqtt->onConnect = function($mqtt) {
        $mqtt->subscribe('mqtt/face/1400754/Snap');
    };
    $mqttService = new MqttService();
    $mqtt->onMessage = function($topic, $content) use ($mqttService){
        $mqttService->handlerMessage($topic,$content);
        //var_dump($topic, $content);
    };
    $mqtt->connect();
};
Worker::runAll();

业务代码, $mqttService->handlerMessage里的逻辑:

public function handlerMessage($topic,$content) {
        if (!empty($topic)) {
            //echo "topic:".$topic.'\r\n';
            Log::info($topic);
            Log::info($content);
        }
}

完整异常trace:

TypeError: Argument 1 passed to support\Log::handlers() must be of the type array, null given, called in D:\develop\php\webman_admin\vendor\workerman\webman-framework\src\support\Log.php
 on line 55 and defined in D:\develop\php\webman_admin\vendor\workerman\webman-framework\src\support\Log.php:67
Stack trace:
#0 D:\develop\php\webman_admin\vendor\workerman\webman-framework\src\support\Log.php(55): support\Log::handlers(NULL)
#1 D:\develop\php\webman_admin\vendor\workerman\webman-framework\src\support\Log.php(139): support\Log::channel()
#2 D:\develop\php\webman_admin\app\mqttService\MqttService.php(26): support\Log::__callStatic('info', Array)
#3 D:\develop\php\webman_admin\mqtt_subscribe.php(21): app\mqttService\MqttService->handlerMessage('mqtt/face/basic', '{\r\n"operator": ...')
#4 [internal function]: {closure}('mqtt/face/basic', '{\r\n"operator": ...', Object(Workerman\Mqtt\Client))
#5 D:\develop\php\webman_admin\vendor\workerman\mqtt\src\Client.php(599): call_user_func(Object(Closure), 'mqtt/face/basic', '{\r\n"operator": ...', Object(Workerman\Mqtt\Client))       
#6 D:\develop\php\webman_admin\vendor\workerman\workerman\Connection\TcpConnection.php(646): Workerman\Mqtt\Client->onConnectionMessage(Object(Workerman\Connection\AsyncTcpConnection), A
rray)
#7 D:\develop\php\webman_admin\vendor\workerman\workerman\Events\Select.php(311): Workerman\Connection\TcpConnection->baseRead(Resource id #42)
#8 D:\develop\php\webman_admin\vendor\workerman\workerman\Worker.php(1479): Workerman\Events\Select->loop()
#9 D:\develop\php\webman_admin\vendor\workerman\workerman\Worker.php(1399): Workerman\Worker::forkWorkersForWindows()
#10 D:\develop\php\webman_admin\vendor\workerman\workerman\Worker.php(560): Workerman\Worker::forkWorkers()
#11 D:\develop\php\webman_admin\mqtt_subscribe.php(27): Workerman\Worker::runAll()
#12 {main}
953 3 4
3个回答

allen2910

我的目的就是想用workerman/mqtt消费消息,然后使用webman的数据库,redis等组件写业务

  • 暂无评论
walkor

webman启动时会读取配置初始化webman运行环境,初始化support\Log。但是你的mqtt_subscribe.php是一个单独脚本,不是webman的一部分,缺少这些初始化,所以无法使用support\Log。

你可以参考webman自定义进程部分,将你的mqtt业务放到webman自定义进程中运行,这样就能用webman的运行环境了。

  • allen2910 2023-04-22

    已经成功了,但是有个问题,就是会报一个错: Uncaught Exception: class \Protocols\Mqtt not exist,我看了也确实没有这个类:我直接在onWorkerStart初始化,但是就不会onConnect和onMessage了,很尴尬,还是需要写进协议里:

    class MqttClient
    {
        private ?Client $mqtt = null;
    
        public function onWorkerStart()
        {
            Log::info("启动了:");
            if (empty($this->mqtt)) {
                $options = [
                    'username' => 'admin',
                    'password' => '123456',
                ];
                $this->mqtt = new Client('mqtt://192.168.1.5:1883',$options);
                $this->mqtt->subscribe('mqtt/test/1400754/Snap');
                Log::info("执行初始化了:");
            }
    
            Log::info("启动了1:");
        }
    
        public function onConnect(TcpConnection $connection)
        {
    //        $options = [
    //            'username' => 'admin',
    //            'password' => '123456',
    //        ];
    //        $this->mqtt = new Client('mqtt://192.168.1.5:1883',$options);
    //        $this->mqtt->subscribe('mqtt/face/1400754/Snap');
            Log::info("连上mqtt了");
        }
    
        public function onMessage(TcpConnection $connection, $data)
        {
            Log::info("接收数据:".$data);
            echo $connection->id.'\r\n';
            echo $data.'\r\n';
    //        echo "消息来了\r\n";
    //        $connection->send($data);
    //        $mqttHandler = new MqttHandler();
    //        $mqttHandler->handlerMessage($topic,$content);
        }
    
        public function onClose(TcpConnection $connection)
        {
            echo "onClose\n";
        }
    }
  • walkor 2023-04-22

    你看下是不是用错客户端了,用Workerman\Mqtt\Client。
    MqttClient作为服务端有监听端口时,有客户端连接监听的端口请求时才会触发MqttClient的onConnect和onMessage,否则不会触发。

  • allen2910 2023-04-22

    用上了,现在连上了,不过有个问题,就是不会触发onConnet,onMessage

    <?php
    
    namespace process;
    
    use support\Log;
    use Workerman\Connection\TcpConnection;
    use Workerman\Mqtt\Client;
    
    class MqttClient
    {
        private ?Client $mqtt = null;
    
        public function onWorkerStart()
        {
            Log::info("启动了:");
            if (empty($this->mqtt)) {
                $options = [
                    'username' => 'admin',
                    'password' => '123456',
                ];
                $this->mqtt = new Client('mqtt://192.168.1.5:1883',$options);
                $this->mqtt->connect();
                Log::info("执行初始化了:"); // 这里执行了
            }
    
            Log::info("启动了1:");
        }
    
        public function onConnect(TcpConnection $connection)
        {
            echo $connection->id.'\r\n';
    //        $options = [
    //            'username' => 'admin',
    //            'password' => '123456',
    //        ];
    //        $this->mqtt = new Client('mqtt://192.168.1.5:1883',$options);
    //        $this->mqtt->subscribe('mqtt/face/1400754/Snap');
            $this->mqtt->subscribe('mqtt/test/1400754/Snap');
            Log::info("连上mqtt了"); // 这里没有执行
        }
    
        public function onMessage(TcpConnection $connection, $data)
        {
            Log::info("接收数据:".$data); // 这里也没有执行
            echo $connection->id.'\r\n';
            echo $data.'\r\n';
    //        echo "消息来了\r\n";
    //        $connection->send($data);
    //        $mqttHandler = new MqttHandler();
    //        $mqttHandler->handlerMessage($topic,$content);
        }
    
        public function onClose(TcpConnection $connection)
        {
            $this->mqtt->close();
            $this->mqtt = null;
            echo "onClose\n";
        }
    
    }

    之前单独使用Workerman\Mqtt\Client这个组件是可以接收连接和消息的

  • allen2910 2023-04-22

    服务器也接收到消息请求消息了

    {"type":1,"protocol_name":"MQTT","protocol_level":4,"clean_session":1,"user_name":"admin","password":"123456","keep_alive":50,"client_id":"workerman-mqtt-client-649296651"}

    就是后续消息没有接收到,很奇怪

  • allen2910 2023-04-22

    紧接着webman 客户端就报错:Mqtt client: No connection to broker

  • allen2910 2023-04-22

    大佬们,是不是我的姿势不对?感觉要不自己用workerman/mqtt组件+mysql组件+redis组件自己搭一个简易的小项目

  • walkor 2023-04-22
    <?php
    
    namespace app\process;
    
    class MqttClient
    {
        public function onWorkerStart()
        {
            $mqtt = new \Workerman\Mqtt\Client('mqtt://broker.emqx.io:1883', array(
                'debug' => true,
                "username"=>"rw", "password"=>"readwrite"
            ));
            $mqtt->onConnect = function($mqtt) {
                $mqtt->subscribe('workerman');
            };
            $mqtt->onMessage = function($topic, $content){
                echo "topic:$topic content:$content\n";
            };
            \Workerman\Timer::add(2, function() use ($mqtt) {
                $mqtt->publish('workerman', 'hello workerman mqtt');
            });
            $mqtt->connect();
        }
    }

    类似设置$mqtt->onConnect = function(){};,$mqtt客户端不会出发你的public onConnect(){},因为public onConnect(){}是作为服务端才能触发的。onMessage也一样,别搞混了

  • allen2910 2023-04-23

    好的,感觉大佬,已经可以了

PHP甩JAVA一条街

大佬们说的我都看不懂

  • 暂无评论
年代过于久远,无法发表回答
🔝