今天我们学习一下rabbitMQ在php的基本使用。已yii2框架为例。
在这我们将用PHP编写两个程序,生产者发送一个消息,消费者接收信息并打印出来。在使用php-amqplib API时我们会掩盖一些细节,把精力集中在这个非常简单的事情开始。这是一个“Hello World”的消息。
一、安装php-amqplib库
1、composer 安装
{
"require": {
"php-amqplib/php-amqplib": "*"
}
}
2、git 安装
git clone [email protected]:php-amqplib/php-amqplib.git
二、配置yii2服务端控制台命令(console)。具体配置,请查看下面链接。
https://blog.csdn.net/weixin_36851500/article/details/92798246
三、现在我们已经安装了php-amqplib库,我们可以写一些代码
目录 /yii2advanced/vendor/yiisoft/yii2/console/controllers 下创建 ProducerController.php和ConsumerController.php
1、发送信息
我们将调用我们消息发送者 ProducerController.php,并调用我们的消息接收者 ConsumerController.php 。消息发送者将要连接RabbitMQ,发送一个消息,然后退出。
- 在ProducerController.php中,我们需要包含库和使用必要的类:
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
- 然后我们可以建立一个到RabbitMQ服务器的连接:
$amqp = yii::$app->params['amqp'];
//建立一个到RabbitMQ服务器的连接
$this->connection = new AMQPStreamConnection($amqp["host"], $amqp["port"], $amqp["user"], $amqp["password"]);
$this->channel = $this->connection->channel();
- 要发送,我们必须为我们发送声明一个队列,然后我们可以向队列发布消息:
//接下来,我们创建一个通道,这是大部分的API来完成任务所在。
$channel->queue_declare('hello', false, false, false, false);
//构建消息体
$msg = new AMQPMessage('Hello World!');
//发送信息
$channel->basic_publish($msg,'','hello');
echo " [x] Sent 'Hello World!'\n";
- 最后,我们关闭通道和连接;
$channel->close();
$connection->close();
发送不成功!
如果这是你第一次使用RabbitMQ,并且没有看到“Sent”消息出现在屏幕上,你可能会抓耳挠腮不知所以。这也许是因为没有足够的磁盘空间给代理使用所造成的(代理默认需要1Gb的空闲空间),所以它才会拒绝接收消息。查看一下代理的日志确定并且减少必要的限制。配置文件文档会告诉你如何更改磁盘空间限制(disk_free_limit)。
2、获取数据
那是我们的发送者。我们的接受者获取从RabbitMQ推过来的消息,所以不像发送者发布一个消息,我们将保持运行监听消息并打印出来
- 代码(在 ConsumerController.php )具有几乎相同的包括和加载:
use PhpAmqpLib\Connection\AMQPStreamConnection;
- 设置和发送者是一样的,我们打开一个连接和一个通道,然后声明我们将要消耗的队列。请注意,这与发送的队列中的队列相匹配。
然后我们可以建立一个到RabbitMQ服务器的连接:
$amqp = yii::$app->params['amqp'];
//建立一个到RabbitMQ服务器的连接
$this->connection = new AMQPStreamConnection($amqp["host"], $amqp["port"], $amqp["user"], $amqp["password"]);
$this->channel = $this->connection->channel();
建立通道
$connection = $this->connection;
$channel = $this->channel;
$channel->queue_declare('hello', false, false, false, false);
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
请注意,我们在这里声明队列。因为在发送者之前,我们可以启动接收者,所以我们希望在尝试消费它的消息之前先确保队列的存在。
我们将要告诉服务器从队列中传递消息。我们将定义一个PHP回调将接收服务器发送的消息。请记住,消息是从服务器异步发送到客户端的。
$callback = function($msg){
echo " [x] Received ", $msg->body, "\n";
};
$channel->basic_consume('hello', '', false, true, false, false, $callback);
while(count($channel->callbacks)) {
$channel->wait();
}
$channel->close();
$connection->close();
代码块循环 通道( callback)将传递给接收的消息。
四、整合
- 现在就可以在终端中运行我们的程序了。启动发送者:
./yii rabbitmq-producer/send
- 然后启动消费者
./yii rabbitmq-consumer/receive
接收者将打印从发送者通过RabbitMQ发送的消息。接收器将继续运行,等待消息(使用Ctrl-C来中止),所以试着从另一个终端运行发件者。
- 如果你想查看Rabbitmq队列,并且想知道有多少消息存在其中,你(作为特权用户)可以使用rabbitmqctl 工具
sudo rabbitmqctl list_queues
五、 源码
1、创建 ProducerController.php 生产者类 actionSend 方法
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* 生产者 发送信息
*/
namespace yii\console\controllers;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\console\Controller;
use yii\console\Exception;
use yii\console\ExitCode;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use yii\test\FixtureTrait;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
/**
* Manages fixture data loading and unloading.
*
* ```
* #load fixtures from UsersFixture class with default namespace "tests\unit\fixtures"
* yii fixture/load User
*
* #also a short version of this command (generate action is default)
* yii fixture User
*
* #load all fixtures
* yii fixture "*"
*
* #load all fixtures except User
* yii fixture "*, -User"
*
* #load fixtures with different namespace.
* yii fixture/load User --namespace=alias\my\custom\namespace\goes\here
* ```
*
* The `unload` sub-command can be used similarly to unload fixtures.
*
* @author Mark Jebri <[email protected]>
* @since 2.0
*/
class ProducerController extends Controller
{
private $channel;
private $connection;
public function init ()
{
$amqp = yii::$app->params['amqp'];
//建立一个到RabbitMQ服务器的连接
$this->connection = new AMQPStreamConnection($amqp["host"], $amqp["port"], $amqp["user"], $amqp["password"]);
$this->channel = $this->connection->channel();
}
/**
* Hello World 发送信息
*/
public function actionSend(){
try {
//建立一个到RabbitMQ服务器的连接
$connection = $this->connection;
$channel = $this->channel;
//接下来,我们创建一个通道,这是大部分的API来完成任务所在。
$channel->queue_declare('hello', false, false, false, false);
//构建消息体
$msg = new AMQPMessage('Hello World!');
//发送信息
$channel->basic_publish($msg,'','hello');
echo " [x] Sent 'Hello World!'\n";
$channel->close();
$connection->close();
} catch(\Exception $e)
{
echo $e->getMessage();
}
}
}
2、ConsumerController.php 消费者文件类 actionReceive 方法
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* 消费者 接收信息
*/
namespace yii\console\controllers;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\console\Controller;
use yii\console\Exception;
use yii\console\ExitCode;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use yii\test\FixtureTrait;
use common\tools\Pusher;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
/**
* Manages fixture data loading and unloading.
*
* ```
* #load fixtures from UsersFixture class with default namespace "tests\unit\fixtures"
* yii fixture/load User
*
* #also a short version of this command (generate action is default)
* yii fixture User
*
* #load all fixtures
* yii fixture "*"
*
* #load all fixtures except User
* yii fixture "*, -User"
*
* #load fixtures with different namespace.
* yii fixture/load User --namespace=alias\my\custom\namespace\goes\here
* ```
*
* The `unload` sub-command can be used similarly to unload fixtures.
*
* @author Mark Jebri <[email protected]>
* @since 2.0
*/
class ConsumerController extends Controller
{
private $channel;
private $connection;
public function init ()
{
$amqp = yii::$app->params['amqp'];
//建立一个到RabbitMQ服务器的连接
$this->connection = new AMQPStreamConnection($amqp["host"], $amqp["port"], $amqp["user"], $amqp["password"]);
$this->channel = $this->connection->channel();
}
/**
* Loads the specified fixture data.
* @return bool
* Hello World 接收信息
*/
public function actionReceive(){
try {
//$channel = $this->channel;
//var_dump($this->channel);exit;
//设置和发送者是一样的,我们打开一个连接和一个通道,然后声明我们将要消耗的队列。请注意,这与发送的队列中的队列相匹配。
//建立一个到RabbitMQ服务器的连接
$connection = $this->connection;
$channel = $this->channel;
$channel->queue_declare('hello', false, false, false, false);
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
$callback = function($msg){
echo " [x] Received ", $msg->body, "\n";
// $msg->delivery_info['channel']->basic_ack(
// $msg->delivery_info['delivery_tag']);
};
$channel->basic_consume('hello', '', false, true, false, false, $callback);
while(count($channel->callbacks)) {
$channel->wait();
}
$channel->close();
$connection->close();
} catch(\Exception $e)
{
echo $e->getMessage();
}
}
}
有兴趣的话,可以多了解一下其他的文章:
https://xiaoxiami.gitbook.io/rabbitmq_into_chinese_php/ying-yong-jiao-cheng/php-ban/1-hello_world