PHP+RabbitMQ实现消息队列的完整代码


Posted in PHP onMarch 20, 2019

前言

为什么使用RabbitMq而不是ActiveMq或者RocketMq?

首先,从业务上来讲,我并不要求消息的100%接受率,并且,我需要结合php开发,RabbitMq相较RocketMq,延迟较低(微妙级)。至于ActiveMq,貌似问题较多。RabbitMq对各种语言的支持较好,所以选择RabbitMq。

先安装PHP对应的RabbitMQ,这里用的是 php_amqp 不同的扩展实现方式会有细微的差异.

php扩展地址: http://pecl.php.net/package/amqp

具体以官网为准  http://www.rabbitmq.com/getstarted.html

介绍

  • config.php 配置信息
  • BaseMQ.php MQ基类
  • ProductMQ.php 生产者类
  • ConsumerMQ.php 消费者类
  • Consumer2MQ.php 消费者2(可有多个)

config.php

<?php
 return [
  //配置
  'host' => [
   'host' => '127.0.0.1',
   'port' => '5672',
   'login' => 'guest',
   'password' => 'guest',
   'vhost'=>'/',
  ],
  //交换机
  'exchange'=>'word',
  //路由
  'routes' => [],
 ];

BaseMQ.php

<?php
 /**
  * Created by PhpStorm.
  * User: pc
  * Date: 2018/12/13
  * Time: 14:11
  */
 
 namespace MyObjSummary\rabbitMQ;
 
 /** Member
  *  AMQPChannel
  *  AMQPConnection
  *  AMQPEnvelope
  *  AMQPExchange
  *  AMQPQueue
  * Class BaseMQ
  * @package MyObjSummary\rabbitMQ
  */
 class BaseMQ
 {
  /** MQ Channel
   * @var \AMQPChannel
   */
  public $AMQPChannel ;
 
  /** MQ Link
   * @var \AMQPConnection
   */
  public $AMQPConnection ;
 
  /** MQ Envelope
   * @var \AMQPEnvelope
   */
  public $AMQPEnvelope ;
 
  /** MQ Exchange
   * @var \AMQPExchange
   */
  public $AMQPExchange ;
 
  /** MQ Queue
   * @var \AMQPQueue
   */
  public $AMQPQueue ;
 
  /** conf
   * @var
   */
  public $conf ;
 
  /** exchange
   * @var
   */
  public $exchange ;
 
  /** link
   * BaseMQ constructor.
   * @throws \AMQPConnectionException
   */
  public function __construct()
  {
   $conf = require 'config.php' ;
   if(!$conf)
    throw new \AMQPConnectionException('config error!');
   $this->conf  = $conf['host'] ;
   $this->exchange = $conf['exchange'] ;
   $this->AMQPConnection = new \AMQPConnection($this->conf);
   if (!$this->AMQPConnection->connect())
    throw new \AMQPConnectionException("Cannot connect to the broker!\n");
  }
 
  /**
   * close link
   */
  public function close()
  {
   $this->AMQPConnection->disconnect();
  }
 
  /** Channel
   * @return \AMQPChannel
   * @throws \AMQPConnectionException
   */
  public function channel()
  {
   if(!$this->AMQPChannel) {
    $this->AMQPChannel = new \AMQPChannel($this->AMQPConnection);
   }
   return $this->AMQPChannel;
  }
 
  /** Exchange
   * @return \AMQPExchange
   * @throws \AMQPConnectionException
   * @throws \AMQPExchangeException
   */
  public function exchange()
  {
   if(!$this->AMQPExchange) {
    $this->AMQPExchange = new \AMQPExchange($this->channel());
    $this->AMQPExchange->setName($this->exchange);
   }
   return $this->AMQPExchange ;
  }
 
  /** queue
   * @return \AMQPQueue
   * @throws \AMQPConnectionException
   * @throws \AMQPQueueException
   */
  public function queue()
  {
   if(!$this->AMQPQueue) {
    $this->AMQPQueue = new \AMQPQueue($this->channel());
   }
   return $this->AMQPQueue ;
  }
 
  /** Envelope
   * @return \AMQPEnvelope
   */
  public function envelope()
  {
   if(!$this->AMQPEnvelope) {
    $this->AMQPEnvelope = new \AMQPEnvelope();
   }
   return $this->AMQPEnvelope;
  }
 }

ProductMQ.php

<?php
 //生产者 P
 namespace MyObjSummary\rabbitMQ;
 require 'BaseMQ.php';
 class ProductMQ extends BaseMQ
 {
  private $routes = ['hello','word']; //路由key
 
  /**
   * ProductMQ constructor.
   * @throws \AMQPConnectionException
   */
  public function __construct()
  {
   parent::__construct();
  }
 
  /** 只控制发送成功 不接受消费者是否收到
   * @throws \AMQPChannelException
   * @throws \AMQPConnectionException
   * @throws \AMQPExchangeException
   */
  public function run()
  {
   //频道
   $channel = $this->channel();
   //创建交换机对象
   $ex = $this->exchange();
   //消息内容
   $message = 'product message '.rand(1,99999);
   //开始事务
   $channel->startTransaction();
   $sendEd = true ;
   foreach ($this->routes as $route) {
    $sendEd = $ex->publish($message, $route) ;
    echo "Send Message:".$sendEd."\n";
   }
   if(!$sendEd) {
    $channel->rollbackTransaction();
   }
   $channel->commitTransaction(); //提交事务
   $this->close();
   die ;
  }
 }
 try{
  (new ProductMQ())->run();
 }catch (\Exception $exception){
  var_dump($exception->getMessage()) ;
 }

ConsumerMQ.php

<?php
 //消费者 C
 namespace MyObjSummary\rabbitMQ;
 require 'BaseMQ.php';
 class ConsumerMQ extends BaseMQ
 {
  private $q_name = 'hello'; //队列名
  private $route = 'hello'; //路由key
 
  /**
   * ConsumerMQ constructor.
   * @throws \AMQPConnectionException
   */
  public function __construct()
  {
   parent::__construct();
  }
 
  /** 接受消息 如果终止 重连时会有消息
   * @throws \AMQPChannelException
   * @throws \AMQPConnectionException
   * @throws \AMQPExchangeException
   * @throws \AMQPQueueException
   */
  public function run()
  {
 
   //创建交换机
   $ex = $this->exchange();
   $ex->setType(AMQP_EX_TYPE_DIRECT); //direct类型
   $ex->setFlags(AMQP_DURABLE); //持久化
   //echo "Exchange Status:".$ex->declare()."\n";
 
   //创建队列
   $q = $this->queue();
   //var_dump($q->declare());exit();
   $q->setName($this->q_name);
   $q->setFlags(AMQP_DURABLE); //持久化
   //echo "Message Total:".$q->declareQueue()."\n";
 
   //绑定交换机与队列,并指定路由键
   echo 'Queue Bind: '.$q->bind($this->exchange, $this->route)."\n";
 
   //阻塞模式接收消息
   echo "Message:\n";
   while(True){
    $q->consume(function ($envelope,$queue){
     $msg = $envelope->getBody();
     echo $msg."\n"; //处理消息
     $queue->ack($envelope->getDeliveryTag()); //手动发送ACK应答
    });
    //$q->consume('processMessage', AMQP_AUTOACK); //自动ACK应答
   }
   $this->close();
  }
 }
 try{
  (new ConsumerMQ)->run();
 }catch (\Exception $exception){
  var_dump($exception->getMessage()) ;
 }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
PHP入门学习的几个不错的实例代码
Jul 13 PHP
php下几个常用的去空、分组、调试数组函数
Feb 22 PHP
PHP实现数组递归转义的方法
Aug 28 PHP
PHP实现简单数字分页效果
Jul 26 PHP
Zend Framework入门之环境配置及第一个Hello World示例(附demo源码下载)
Mar 21 PHP
php is_executable判断给定文件名是否可执行实例
Sep 26 PHP
php正则提取html图片(img)src地址与任意属性的方法
Feb 08 PHP
PHP实现的数独求解问题示例
Apr 18 PHP
PHPstorm快捷键(分享)
Jul 17 PHP
PHP Socket网络操作类定义与用法示例
Aug 30 PHP
php微信开发之谷歌测距
Jun 14 PHP
解决laravel id非自增 模型取回为0 的问题
Oct 11 PHP
PHP实现的数据对象映射模式详解
Mar 20 #PHP
PHP单例模式数据库连接类与页面静态化实现方法
Mar 20 #PHP
PHP实现的策略模式示例
Mar 20 #PHP
PHP实现数组和对象的相互转换操作示例
Mar 20 #PHP
Laravel5.4框架使用socialite实现github登录的方法
Mar 20 #PHP
PHP工厂模式的日常使用
Mar 20 #PHP
PHP函数积累总结
Mar 19 #PHP
You might like
php获取操作系统语言代码
2013/11/04 PHP
Symfony控制层深入详解
2016/03/17 PHP
PHP7.1方括号数组符号多值复制及指定键值赋值用法分析
2016/09/26 PHP
thinkPHP5框架自定义验证器实现方法分析
2018/06/11 PHP
细说浏览器特性检测(2)-通用事件检测
2010/11/05 Javascript
JS中prototype关键字的功能介绍及使用示例
2013/07/21 Javascript
jquery制作搜狐快站页面效果示例分享
2014/02/21 Javascript
JavaScript实现同一页面内两个表单互相传值的方法
2015/08/12 Javascript
JavaScript事件类型中UI事件详解
2016/01/14 Javascript
jQuery筛选数组之grep、each、inArray、map的用法及遍历json对象
2016/06/20 Javascript
JavaScript 链式结构序列化详解
2016/09/30 Javascript
轻松学习Javascript闭包
2017/03/01 Javascript
Vue和Bootstrap的整合思路详解
2017/06/30 Javascript
详解在WebStorm中添加Vue.js单文件组件的高亮及语法支持
2017/10/21 Javascript
Vue 实现展开折叠效果的示例代码
2018/08/27 Javascript
优雅的在React项目中使用Redux的方法
2018/11/10 Javascript
在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法
2019/08/22 Javascript
js中!和!!的区别与用法
2020/05/09 Javascript
vue+animation实现翻页动画
2020/06/29 Javascript
[03:59]第二届DOTA2亚洲邀请赛选手传记-VGJ.rOtk
2017/04/03 DOTA
python发送伪造的arp请求
2014/01/09 Python
Python中使用ConfigParser解析ini配置文件实例
2014/08/30 Python
tensorflow创建变量以及根据名称查找变量
2018/03/10 Python
在ubuntu16.04中将python3设置为默认的命令写法
2018/10/31 Python
python3 实现验证码图片切割的方法
2018/12/07 Python
Python多项式回归的实现方法
2019/03/11 Python
python基于json文件实现的gearman任务自动重启代码实例
2019/08/13 Python
python实现一个简单RPC框架的示例
2020/10/28 Python
SQL Server里面什么样的视图才能创建索引
2015/04/17 面试题
志愿者活动总结
2014/04/28 职场文书
党员政治学习材料
2014/05/14 职场文书
2014年车间主任工作总结
2014/12/10 职场文书
介绍信格式样本
2015/05/05 职场文书
中学教代会开幕词
2016/03/04 职场文书
Python图片验证码降噪和8邻域降噪
2021/08/30 Python
frg-100简单操作(设置)说明
2022/04/05 无线电