thinkphp+swoole+redis发布订阅小试牛刀

感谢swoole,让PHP可以做成之前好多不可能的功能,大大提高了效率,闲来无事做了一个thinkphp+swoole+redis发布订阅DEMO,欢迎吐槽指正!

前言

thinkphp+swoole+redis发布订阅小试牛刀

thinkphp采用的是6.0的版本,swoole的版本为4.3,都是2020年最新的,我看网上的好多教程thinkphp都是3.2(不是藐视,感觉过时了),话不多说,上代码

1、发布端的代码

如何配置thinkphp我就不多讲了,如果真有不会的,可以留言,我可以写一篇教程

public function index()
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
        $redis->auth('123456');
        // test为发布的频道名称,getRandomString方法为生成随机字符串,方便压测
        $msg = self::getRandomString(6);
        $res = $redis->publish('channel1',$msg);
        if ($res){
            return json(['code'=>1000,'msg'=>'success']);
        }
    }

2、订阅端的代码

没有用thinkphp自带的那个swoole,自己写了command来执行,方便后期的启动和停止,在console.php的配置新增一个命令

return [
    // 指令定义
    'commands' => [
        'RedSwoole'=>'app\command\RedSwoole'
    ],
];

在相应的目录创建命令文件:

<?php
namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use Swoole\Process;

class RedSwoole extends Command
{

    protected $server;

    protected function configure()
    {
        $this->setName('RedSwoole')
            ->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload", 'start')
            ->addOption('daemon', 'd', Option::VALUE_NONE, '该进程已后台运行')
            ->setDescription('Start red服务!');
    }

    protected function execute(Input $input, Output $output)
    {
        $action = trim($input->getArgument('action'));
        if (in_array($action, ['start', 'stop', 'reload', 'restart'])) {
            $this->$action();
        } else {
            $output->writeln("<error>传入参数错误:{$action}, 仅支持 start|stop|restart|reload 参数 .</error>");
        }
    }
    public function onWorkerStart($server, $worker_id)
    {
        if ($worker_id == 0){
            $redis = new \Swoole\Coroutine\Redis();
            $redis->connect('127.0.0.1', 6379);
            $redis->auth('123456');
            if ($redis->subscribe(['channel1'])) // 或者使用psubscribe
            {
                while ($msg = $redis->recv()) {
                    // msg是一个数组, 包含以下信息
                    // $type # 返回值的类型:显示订阅成功
                    // $name # 订阅的频道名字 或 来源频道名字
                    // $info  # 目前已订阅的频道数量 或 信息内容
                    list($type, $name, $info) = $msg;
                    if ($type == 'subscribe') {// 或psubscribe

                    }else if ($type == 'unsubscribe' && $info == 0) { // 或punsubscribe
                        break; // 收到取消订阅消息,并且剩余订阅的频道数为0,不再接收,结束循环
                    }else if ($type == 'message') { // 若为psubscribe,此处为pmessage
                        // 打印来源频道名字
                        var_dump($name);
                        // 打印消息
                        var_dump($info);
                    }
                }
            }
        }
    }

    public function onReceive($server, $fd, $reactor_id, $data)
    {

        $server->send($fd, json_encode(['msg' => '收到', 'code' => 200]));
        $server->close($fd);
    }

    protected function start()
    {
        $pid = $this->getMasterPid();
        if ($this->isRunning($pid)) {
            $this->output->writeln('<error>其他临时服务正在运行!!!</error>');
            return false;
        }
        $this->output->writeln('启动red服务...');
        sleep(1);

        $options = [
            'daemonize'  => false,
            'worker_num' => 4,
            'pid_file'   => runtime_path() . 'red_pid',
            'log_file'   => runtime_path() . 'red_log_file',
        ];
        // 开启守护进程模式
        if ($this->input->hasOption('daemon')) {
            $options['daemonize'] = true;
        }
        $this->server = new \Swoole\Server(
            '0.0.0.0',
            '9011',
            SWOOLE_BASE
        );

        $this->server->on('WorkerStart', array($this, 'onWorkerStart'));
        $this->server->on('Receive', array($this, 'onReceive'));
        $this->server->set($options);
        $this->output->writeln('red已启动,地址:0.0.0.0:9011');
        $this->server->start();
    }

    protected function stop()
    {
        $pid = $this->getMasterPid();
        if (!$this->isRunning($pid)) {
            $this->output->writeln('<error>服务未运行!!!</error>');
            return false;
        }
        $this->removePid();
        $this->output->writeln('停止服务中...');
        Process::kill($pid, SIGTERM);
        $this->output->writeln('服务已停止');
    }

    protected function reload()
    {
        $pid = $this->getMasterPid();
        if (!$this->isRunning($pid)) {
            $this->output->writeln('<error>其他临时服务未运行!!!</error>');
            return false;
        }
        $this->output->writeln('服务正在热重启...');
        Process::kill($pid, SIGUSR1);
        $this->output->writeln('服务热重启成功');
    }

    protected function restart()
    {
        $pid = $this->getMasterPid();
        if ($this->isRunning($pid)) {
            $this->stop();
        }
        $this->start();
    }

    protected function getMasterPid()
    {
        if (is_file(runtime_path() . 'red_pid')) {
            $masterPid = (int) file_get_contents(runtime_path() . 'red_pid');
        } else {
            $masterPid = 0;
        }
        return $masterPid;
    }

    protected function isRunning($pid)
    {
        if (empty($pid)) {
            return false;
        }
        return Process::kill($pid, 0);
    }

    protected function removePid()
    {
        if (is_file(runtime_path() . 'red_pid')) {
            unlink(runtime_path() . 'red_pid');
        }
    }
}

代码撸好以后,在项目的根目录执行命令:

php think RedSwoole start

是不是很丝滑??!!

原创文章,作者:小新新,如若转载,请注明出处:https://news36524.com/jishu/272/

发表评论

电子邮件地址不会被公开。 必填项已用*标注