PHP RabbitMQ消息列队


Posted in PHP onMay 11, 2022

业务场景

项目公司是主php做开发的,框架为thinkphp。众所周知,php本身的运行效率存在一定的缺陷,所以如果有一个很复杂很耗时的业务时,必须开发一个常驻内存的程序。首先我想到了php的workerman与swoole,但是这里应上面的标题哈,想将耗时任务交给另一个服务器,同时列队处理。所以这里我想独立部署一个rabbitMQ服务器用于处理列队任务。

当rabbitMQ服务器我们准备好了,建立了一个持久化命名为ceshi的列队,如下:

PHP RabbitMQ消息列队

项目上生产者和消费者的开发我这里全部采用tinkphp6+workerman,为便于管理。这里这么做也是因为发现workerman中对rabbitMQ的文档解释太少了!

所以开始踩坑!

1、首先部署好thinkphp6框架

2、安装workerman扩展

PHP RabbitMQ消息列队

3、生产者

配置一个workerman类

PHP RabbitMQ消息列队

PHP RabbitMQ消息列队

创建的Send类代码如下:

<?php

namespace app\workerman;
use Bunny\Channel;
use Workerman\RabbitMQ\Client;
use think\worker\Server;
class Send extends Server
{
    //websocket地址,一会用于测试。
    protected $socket = 'websocket://127.0.0.1:2345';

    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
{
        //websocket发送过来的消息
        $connection->send('我收到你的信息了:'.$data);
        //rabbitMQ配置
        $options = [
            'host'=>'127.0.0.1',//rabbitMQ IP
            'port'=>5672,//rabbitMQ 通讯端口
            'user'=>'admin',//rabbitMQ 账号
            'password'=>'123456'//rabbitMQ 密码
        ];
        (new Client($options))->connect()->then(function (Client $client) {
            return $client->channel();
        })->then(function (Channel $channel) {
            /**
             * 创建队列(Queue)
             * name: ceshi         // 队列名称
             * passive: false      // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
             * durable: true       // 是否持久化,设置false是存放到内存中RabbitMQ重启后会丢失,
             *                        设置true则代表是一个持久的队列,服务重启之后也会存在,因为服务会把持久化的Queue存放在硬盘上,当服务重启的时候,会重新加载之前被持久化的Queue
             * exclusive: false    // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
             *  auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
             */
            return $channel->queueDeclare('ceshi', false, true, false, false)->then(function () use ($channel) {
                return $channel;
            });
        })->then(function (Channel $channel) use($data){
            echo "发送消息内容:".$data."\n";

            /**
             * 发送消息
             * body 发送的数据
             * headers 数据头,建议 ['content_type' => 'text/plain'],这样消费端是springboot注解接收直接是字符串类型
             * exchange 交换器名称
             * routingKey 路由key
             * mandatory
             * immediate
             * @return bool|PromiseInterface|int
             */

            return $channel->publish($data, ['content_type' => 'text/plain'], '', 'ceshi')->then(function () use ($channel) {
                return $channel;
            });
        })->then(function (Channel $channel) {
            //echo " [x] Sent 'Hello World!'\n";
            $client = $channel->getClient();
            return $channel->close()->then(function () use ($client) {
                return $client;
            });
        })->then(function (Client $client) {
            $client->disconnect();
        });
    }

    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
{

    }

    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
{

    }
    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
{
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
{


    }
}

上述都OK以后咱们可以项目路径下通过命令启动这个生产者:

php think worker:server

PHP RabbitMQ消息列队

测试发送数据:

PHP RabbitMQ消息列队

通过这个网站

连接【ws://127.0.0.1:2345】后发送数据!

PHP RabbitMQ消息列队

前往rabbitMQ控制台

PHP RabbitMQ消息列队

列队中有一条消息产生并且等待了!

这个时候你可能问,如果我发送数据不想通过ws发送而是接口发送怎么办?

笨思路呗:接口给内置服务器发消息->内置服务去发消息给rabbitMQ

PHP RabbitMQ消息列队

将协议改为tcp

然后重新启动服务

PHP RabbitMQ消息列队

然后去tp6创建一个路由接口

PHP RabbitMQ消息列队

接口代码

<?php
namespace app\controller;

use app\BaseController;

class Index extends BaseController
{
    public function index(string $msg)
{
        //连接本地tcp服务
        $client = stream_socket_client('tcp://127.0.0.1:2345', $errno, $errmsg, 1);
        //发送字符串
        fwrite($client, $msg."\n");
        //断开服务
        fclose($client);
        return 'OK';
    }

}

执行结果:

PHP RabbitMQ消息列队

说明接口成功的将数据发送给了本地内置的tcp服务。

PHP RabbitMQ消息列队

同时,内置服务将收到的数据给了rabbitMQ服务列队中。

生产者完成。

4、消费者

同生产者一样新创建一个thinkphp6及安装workerman扩展,注意端口别和生产者冲突!这里我设置的是2346端口

PHP RabbitMQ消息列队

创建的Receive类代码如下:

<?php

namespace app\workerman;
use Bunny\Channel;
use Bunny\Message;
use Workerman\RabbitMQ\Client;
use think\worker\Server;
class Receive extends Server
{
    protected $socket = 'tcp://127.0.0.1:2346';

    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
{

    }

    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
{

    }

    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
{

    }
    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
{
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
{
        //rabbitMQ配置
        $options = [
            'host'=>'127.0.0.1',//rabbitMQ IP
            'port'=>5672,//rabbitMQ 通讯端口
            'user'=>'admin',//rabbitMQ 账号
            'password'=>'123456'//rabbitMQ 密码
        ];
        (new Client($options))->connect()->then(function (Client $client) {
            return $client->channel();
        })->then(function (Channel $channel) {
            /**
             * 创建队列(Queue)
             * name: ceshi         // 队列名称
             * passive: false      // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
             * durable: true       // 是否持久化,设置false是存放到内存中RabbitMQ重启后会丢失,
             *                        设置true则代表是一个持久的队列,服务重启之后也会存在,因为服务会把持久化的Queue存放在硬盘上,当服务重启的时候,会重新加载之前被持久化的Queue
             * exclusive: false    // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
             *  auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
             */
            return $channel->queueDeclare('ceshi', false, true, false, false)->then(function () use ($channel) {
                return $channel;
            });
        })->then(function (Channel $channel) {
            echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
            $channel->consume(
                function (Message $message, Channel $channel, Client $client) {
                    echo "接收消息内容:", $message->content, "\n";
                },
                'ceshi',
                '',
                false,
                true
            );
        });

    }
}

都OK以后咱们可以项目路径下通过命令启动这个消费者:

php think worker:server

此时应该会自动消费掉rabbitMQ中等待的消息!

PHP RabbitMQ消息列队

PHP RabbitMQ消息列队

到这里消费者也就结束啦!

5、整体测试

接下来我用cmd来启动两个服务,然后用接口发送消息和消费测试!

PHP RabbitMQ消息列队

至于具体怎么灵活应用自行开拓大脑哦~

比如php项目有些业务吃力,可以去做个java的消费端,让java来完成任务~

PHP RabbitMQ消息列队

以上就是PHP实现RabbitMQ消息列队的示例代码的详细内容!

PHP 相关文章推荐
PHP二维数组的去重问题解析
Jul 17 PHP
简单的php写入数据库类代码分享
Jul 26 PHP
php中将图片gif,jpg或mysql longblob或blob字段值转换成16进制字符串
Aug 23 PHP
PHP安全性漫谈
Jun 28 PHP
基于MySQL体系结构的分析
May 02 PHP
CI框架中libraries,helpers,hooks文件夹详细说明
Jun 10 PHP
PHP图片自动裁切应付不同尺寸的显示
Oct 16 PHP
PHP命名空间和自动加载类
Apr 03 PHP
详解PHP用substr函数截取字符串中的某部分
Dec 03 PHP
PHP ADODB生成HTML表格函数rs2html功能【附错误处理函数用法】
May 29 PHP
PHP给前端返回一个JSON对象的实例讲解
May 31 PHP
laravel5.5添加echarts实现画图功能的方法
Oct 09 PHP
php解析非标准json、非规范json的方式实例
PHP面试题 wakeup魔法 Ezpop pop序列化与反序列化
PHP正则表达式之RCEService回溯
微信小程序结合ThinkPHP5授权登陆后获取手机号
PHP遍历数组的6种方式总结
Nov 17 #PHP
关于PHP数组迭代器的使用方法实例
php双向队列实例讲解
Nov 17 #PHP
You might like
实用函数3
2007/11/08 PHP
php中数字、字符与对象判断函数用法实例
2014/11/26 PHP
浅谈PHP中其他类型转化为Bool类型
2016/03/28 PHP
PHP Pipeline 实现中间件的示例代码
2020/04/26 PHP
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
JQuery鼠标移到小图显示大图效果的方法
2015/06/10 Javascript
基于Flowplayer打造一款免费的WEB视频播放器附源码
2015/09/06 Javascript
JQuery实现简单的服务器轮询效果实例
2016/03/31 Javascript
JavaScript中push(),join() 函数 实例详解
2016/09/06 Javascript
javascript cookie用法基础教程(概念,设置,读取及删除)
2016/09/20 Javascript
jQuery实现的购物车物品数量加减功能代码
2016/11/16 Javascript
webpack2.0配置postcss-loader的方法
2017/08/17 Javascript
Vue2.0系列之过滤器的使用
2018/03/01 Javascript
完美解决iview 的select下拉框选项错位的问题
2018/03/02 Javascript
vue组件中使用props传递数据的实例详解
2018/04/08 Javascript
Ant Design moment对象和字符串之间的相互转化教程
2020/10/27 Javascript
[06:42]DOTA2每周TOP10 精彩击杀集锦vol.1
2014/06/25 DOTA
[07:54]DOTA2 MV《我的动力鞋》 ImbaTV 出品
2014/11/21 DOTA
[01:52]DOTA2完美大师赛Vega战队趣味视频——kpii老师小课堂
2017/11/25 DOTA
python 的列表遍历删除实现代码
2020/04/12 Python
Python的collections模块中namedtuple结构使用示例
2016/07/07 Python
python数据类型_字符串常用操作(详解)
2017/05/30 Python
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
2017/07/24 Python
Python中的heapq模块源码详析
2019/01/08 Python
Python实现对adb命令封装
2020/03/06 Python
Html5与App的通讯方式详解
2019/10/24 HTML / CSS
全球度假村:Club Med
2017/11/27 全球购物
Myprotein法国官网:欧洲第一运动营养品牌
2019/03/26 全球购物
亚洲领先的设计购物网站:Pinkoi
2020/11/26 全球购物
如何防止同一个帐户被多人同时登录
2013/08/01 面试题
英语系毕业生自荐信
2013/10/31 职场文书
五水共治一句话承诺
2014/05/30 职场文书
社区六一儿童节活动总结
2015/02/11 职场文书
通知书大全
2015/04/27 职场文书
2015年库房工作总结
2015/04/30 职场文书
高一军训感想
2015/08/07 职场文书