插件窝 干货文章 ThinkPHP6框架下使用simps/mqtt连接阿里云物联网平台MQTT时如何解决“SwooleCoroutineClient::connect(): async-io must be used in PHP CLI mode”错误?

ThinkPHP6框架下使用simps/mqtt连接阿里云物联网平台MQTT时如何解决“SwooleCoroutineClient::connect(): async-io must be used in PHP CLI mode”错误?

Swoole Client mqtt 使用 738    来源:    2025-03-15

在使用ThinkPHP6框架结合simps/mqtt库连接阿里云物联网平台MQTT时,遇到“SwooleCoroutineClient::connect(): async-io must be used in PHP CLI mode”错误,通常是因为Swoole的协程客户端需要在CLI模式下运行,而你在Web模式下使用了它。

问题分析

Swoole的协程客户端(Swoole\Coroutine\Client)是为异步IO设计的,通常需要在CLI模式下运行。如果你在Web模式下(例如通过浏览器访问ThinkPHP6应用)使用它,就会触发这个错误。

解决方案

1. 在CLI模式下运行

如果你需要在CLI模式下运行MQTT客户端,可以通过命令行来执行你的PHP脚本。例如:

php think mqtt:start

在这个命令中,mqtt:start是你自定义的命令,用于启动MQTT客户端。你需要在ThinkPHP6中创建一个自定义命令来处理MQTT连接。

2. 创建自定义命令

在ThinkPHP6中,你可以通过命令行工具来创建自定义命令。首先,创建一个命令类:

php think make:command MqttStart

然后在生成的MqttStart类中编写MQTT连接的逻辑:

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use Simps\MQTT\Client;

class MqttStart extends Command
{
    protected function configure()
    {
        $this->setName('mqtt:start')->setDescription('Start MQTT client');
    }

    protected function execute(Input $input, Output $output)
    {
        $client = new Client([
            'host' => 'your-iot-endpoint',
            'port' => 1883,
            'username' => 'your-username',
            'password' => 'your-password',
            'client_id' => 'your-client-id',
        ]);

        $client->connect();

        // 处理MQTT消息
        $client->loop();
    }
}

3. 使用Swoole的HTTP服务器

如果你必须在Web模式下运行,可以考虑使用Swoole的HTTP服务器来替代传统的PHP-FPM或Apache/Nginx。这样你可以在Web模式下使用Swoole的协程功能。

首先,安装Swoole扩展:

pecl install swoole

然后,在ThinkPHP6中配置Swoole HTTP服务器。你可以在config/swoole.php中配置Swoole服务器:

return [
    'host' => '0.0.0.0',
    'port' => 9501,
    'options' => [
        'worker_num' => 4,
        'daemonize' => false,
    ],
];

最后,启动Swoole HTTP服务器:

php think swoole:start

4. 使用异步任务

如果你不想在Web模式下直接使用Swoole协程客户端,可以考虑将MQTT连接逻辑放入异步任务中执行。ThinkPHP6支持队列任务,你可以将MQTT连接逻辑放入队列中执行。

首先,配置队列驱动(例如Redis),然后在任务类中处理MQTT连接:

namespace app\job;

use think\queue\Job;
use Simps\MQTT\Client;

class MqttJob
{
    public function fire(Job $job, $data)
    {
        $client = new Client([
            'host' => 'your-iot-endpoint',
            'port' => 1883,
            'username' => 'your-username',
            'password' => 'your-password',
            'client_id' => 'your-client-id',
        ]);

        $client->connect();

        // 处理MQTT消息
        $client->loop();

        $job->delete();
    }
}

然后,将任务推送到队列中:

\think\facade\Queue::push('app\job\MqttJob');

总结

  • 如果你需要在Web模式下使用Swoole协程客户端,建议使用Swoole HTTP服务器。
  • 如果你可以在CLI模式下运行,建议通过自定义命令来启动MQTT客户端。
  • 如果你不想直接使用Swoole协程客户端,可以考虑使用异步任务来处理MQTT连接。

根据你的实际需求选择合适的解决方案。