rabbitMQ + yii2 (php) Hello World

今天我們學習一下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)。具體配置,會另寫文章進行詳述。

在這裏插入圖片描述
三、現在我們已經安裝了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();

代碼塊循環 通道(channel調調channel )的回調。無論什麼時候我們收到消息我們的回調函數(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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章