rabbitmq的實現(PHP--簡單模式、fanout模式、direct模式、topic模式)

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;

/**
 * @desc: 連接rabbitmq的一些操作,通用
 */

class BasicConnect extends Controller
{
	public $mq_host 		= '192.168.XX.XXX';
	public $mq_port1 		= 5672;
	public $mq_port2 		= 5672;
	public $mq_port3 		= 5673;
	public $mq_user 		= 'XXXX';
	public $mq_passwd 		= 'XXXX';
	public $mq_vhost 		= '/';
	
	public $connection 		= '';
	public function __construct(){
		$host = [
			[
				'host'		=>	$this->mq_host, 
				'port'		=>	$this->mq_port1, 
				'user'		=>	$this->mq_user, 
				'password'	=>	$this->mq_passwd, 
				'vhost'		=>	$this->mq_vhost
			],
			[
				'host'		=>	$this->mq_host, 
				'port'		=>	$this->mq_port2, 
				'user'		=>	$this->mq_user, 
				'password'	=>	$this->mq_passwd, 
				'vhost'		=>	$this->mq_vhost
			],
			[
				'host'		=>	$this->mq_host, 
				'port'		=>	$this->mq_port3, 
				'user'		=>	$this->mq_user, 
				'password'	=>	$this->mq_passwd, 
				'vhost'		=>	$this->mq_vhost
			],
		];
		
		$options = [];
		
		$this->connection = AMQPStreamConnection::create_connection($host,$options);
	}
}

BasicConnect.php

 

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: 簡單模式---生產者
 *			注意:一個生產者,一個消費者,簡單模式。
 */

class SimpleProducer extends BasicConnect
{
	public $exchange 	= 'simple_test_exchange';
	public $queue 		= 'simple_test_queue';
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$channel = $this->connection->channel();
		
		/**
		*	name: $queue    隊列名稱
		*	passive: false  不檢查是否存在同名隊列(don't check if a queue with the same name exists)
		*	durable: true  服務器重啓後隊列將無法生存(the queue will not survive server restarts)
		*	exclusive: false 可以通過其他通道訪問隊列(the queue can be accessed in other channels)
		*	auto_delete: false 一旦通道關閉,隊列將不會被刪除。(the queue won't be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, true, false, false);

		/**
		*	name: $exchange
		*	type: direct
		*	passive: false
		*	durable: true 服務器重啓後交換機將仍存在(the exchange will survive server restarts)
		*	auto_delete: false 一旦頻道關閉,將不會刪除交換。(the exchange won't be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::DIRECT, false, true, false);

		$channel->queue_bind($this->queue, $this->exchange);

		# 僅發送1條數據
		// $messageBody = 'it is a simple message';
		// $message = new AMQPMessage($messageBody,['content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);
		// $channel->basic_publish($message, $this->exchange);
		
		
		# 發送多條數據(注意,僅第一次創建AMQPMessage對象,其它通過setBody複用前面創建的對象)
		$properties = ['content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT];
		
		for($i=1;$i<10;$i++){
			$messageBody = 'it is a simple message:'.$i;
			
			if( $i == 1){
				$message = new AMQPMessage($messageBody, $properties);
			}else{
				$message->setBody($messageBody);
			}
			
			$channel->basic_publish($message, $this->exchange);
		}

		
		
		$channel->close();
		
		$this->connection->close();
	 
		exit;
	}
}

SimpleProducer.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: 簡單模式---消費者
 */

class SimpleConsumer extends BasicConnect
{
	public $exchange 	= 'simple_test_exchange';
	public $queue 		= 'simple_test_queue';
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$consumerTag = 'consumer' . getmypid();
		
		$channel = $this->connection->channel();
		
		/**
		*	name: $queue    隊列名稱
		*	passive: false  
		*	durable: true  服務器重啓後隊列將仍存在(the queue will survive server restarts)
		*	exclusive: false 可以通過其他通道訪問隊列(the queue can be accessed in other channels)
		*	auto_delete: false 一旦通道關閉,隊列將不會被刪除。(the queue won't be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, true, false, false);

		/**
		*	name: $exchange
		*	type: direct
		*	passive: false
		*	durable: true 服務器重啓後交換機將仍存在(the exchange will survive server restarts)
		*	auto_delete: false 一旦頻道關閉,將不會刪除交換。(the exchange won't be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::DIRECT, false, true, false);

		$channel->queue_bind($this->queue, $this->exchange);

		/**
		*	queue: 隊列名稱,從何處獲取消息的隊列(Queue from where to get the messages)
		*	consumer_tag: 消費者標識符(Consumer identifier)
		*	no_local: 不接收此消費者發佈的消息。(Don't receive messages published by this consumer.)
		*	no_ack: 如果設置爲真,則此用戶將使用自動確認模式(If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.)
		*	exclusive: 請求獨佔使用者訪問,這意味着只有此使用者可以訪問隊列(Request exclusive consumer access, meaning only this consumer can access the queue)
		*	nowait: 不要等待服務器響應。如果出現錯誤,服務器將引發通道異常(don't wait for a server response. In case of error the server will raise a channel exception)
		*	callback: 回調函數(A PHP Callback)
		*/
		$channel->basic_consume($this->queue, $consumerTag, false, false, false, false, [new FanoutConsumer1(),'process_message']);

		register_shutdown_function([new FanoutConsumer1(),'shutdown'], $channel, $this->connection);
		
		// 循環,只要通道已註冊回調(Loop as long as the channel has callbacks registered)
		while ($channel->is_consuming()) {
			$channel->wait();
		}

		exit;
	}
	
	/**
	 * 回調函數
	 */
	public function process_message($message){
		echo "\n--------\n";
		echo $message->body;
		echo "\n--------\n";

		$message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

		// 發送字符串“quit”通知消費者退出。(Send a message with the string "quit" to cancel the consumer.)
		if ($message->body === 'quit') {
			$message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
		}
	}
	
	/**
	 * @param \PhpAmqpLib\Channel\AMQPChannel $channel
	 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
	 */
	public function shutdown($channel, $connection)
	{
		$channel->close();
		$connection->close();
	}
}

SimpleConsumer.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: fanout形式---生產者
 *			注意:
	1)、生產者不需要定義隊列名稱,而消費者必須定義隊列名稱
	2)、工作隊列模式(Work Queue):一個生產者,多個消費者同時消費這些數據,即輪詢消費(啓動1個FanoutProducer,啓動多個FanoutConsumer1)
	3)、發佈/訂閱模式(Publish/Subscribe):一個生產者,多個消費者獲得相同的數據,即廣播方式(啓動1個FanoutProducer,啓動多個FanoutConsumer1{需要注意修改其中的queue名稱,保證不一致})
 */

class FanoutProducer extends BasicConnect
{
	public $exchange 	= 'fanout_test_exchange';
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$channel = $this->connection->channel();
	   /**
		*	name: $exchange 交換機名稱
		*	type: fanout   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::FANOUT, false, false, true);
		
		$messageBody = 'I am a fanout message';
		
		$message = new AMQPMessage($messageBody, ['content_type' => 'text/plain']);
		
		$res = $channel->basic_publish($message, $this->exchange);
		
		$channel->close();
		
		$this->connection->close();

		exit;
	}
}

FanoutProducer.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: fanout形式--消費者1
 */

class FanoutConsumer1 extends BasicConnect
{
	public $exchange 	= 'fanout_test_exchange';
	public $queue 		= 'fanout_test_queue1';#注意就這個隊列名不同
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$consumerTag = 'consumer' . getmypid();

		$channel = $this->connection->channel();

	   /**
		*	name: $queue    隊列名稱,在fanout類型的交換機中必須唯一(should be unique in fanout exchange.)
		*	passive: false  不檢查是否存在同名隊列(don't check if a queue with the same name exists)
		*	durable: false  服務器重啓後隊列將無法生存(the queue will not survive server restarts)
		*	exclusive: false 隊列可能被其他通道訪問(the queue might be accessed by other channels)
		*	auto_delete: true 一旦通道關閉,隊列將被刪除(the queue will be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, false, false, true);

	   /**
		*	name: $exchange 交換機名稱
		*	type: fanout   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::FANOUT, false, false, true);

		$channel->queue_bind($this->queue, $this->exchange);

		
		/*
		*	queue: 隊列名稱,從何處獲取消息的隊列(Queue from where to get the messages)
		*	consumer_tag: 消費者標識符(Consumer identifier)
		*	no_local: 不接收此消費者發佈的消息。(Don't receive messages published by this consumer.)
		*	no_ack: 如果設置爲真,則此用戶將使用自動確認模式(If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.)
		*	exclusive: 請求獨佔使用者訪問,這意味着只有此使用者可以訪問隊列(Request exclusive consumer access, meaning only this consumer can access the queue)
		*	nowait: 不要等待服務器響應。如果出現錯誤,服務器將引發通道異常(don't wait for a server response. In case of error the server will raise a channel exception)
		*	callback: 回調函數(A PHP Callback)
		*/

		$channel->basic_consume($this->queue, $consumerTag, false, false, false, false, [new FanoutConsumer1(),'process_message']);

		register_shutdown_function([new FanoutConsumer1(),'shutdown'], $channel, $this->connection);

		// 循環,只要通道已註冊回調(Loop as long as the channel has callbacks registered)
		while ($channel->is_consuming()) {
			$channel->wait();
		}

		exit;
	}
	
	/**
	 * 回調函數
	 */
	public function process_message($message){
		echo "\n--------\n";
		echo $message->body;
		echo "\n--------\n";

		$message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

		// 發送字符串“quit”通知消費者退出。(Send a message with the string "quit" to cancel the consumer.)
		if ($message->body === 'quit') {
			$message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
		}
	}
	
	/**
	 * @param \PhpAmqpLib\Channel\AMQPChannel $channel
	 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
	 */
	public function shutdown($channel, $connection)
	{
		$channel->close();
		$connection->close();
	}

}

FanoutConsumer1.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: fanout形式--消費者2
 */

class FanoutConsumer2 extends BasicConnect
{
	public $exchange 	= 'fanout_test_exchange';
	public $queue 		= 'fanout_test_queue2';#注意就這個隊列名不同
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$consumerTag = 'consumer' . getmypid();

		$channel = $this->connection->channel();

	   /**
		*	name: $queue    隊列名稱,在fanout類型的交換機中必須唯一(should be unique in fanout exchange.)
		*	passive: false  不檢查是否存在同名隊列(don't check if a queue with the same name exists)
		*	durable: false  服務器重啓後隊列將無法生存(the queue will not survive server restarts)
		*	exclusive: false 隊列可能被其他通道訪問(the queue might be accessed by other channels)
		*	auto_delete: true 一旦通道關閉,隊列將被刪除(the queue will be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, false, false, true);

	   /**
		*	name: $exchange 交換機名稱
		*	type: fanout   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::FANOUT, false, false, true);

		$channel->queue_bind($this->queue, $this->exchange);

		
		/*
		*	queue: 隊列名稱,從何處獲取消息的隊列(Queue from where to get the messages)
		*	consumer_tag: 消費者標識符(Consumer identifier)
		*	no_local: 不接收此消費者發佈的消息。(Don't receive messages published by this consumer.)
		*	no_ack: 如果設置爲真,則此用戶將使用自動確認模式(If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.)
		*	exclusive: 請求獨佔使用者訪問,這意味着只有此使用者可以訪問隊列(Request exclusive consumer access, meaning only this consumer can access the queue)
		*	nowait: 不要等待服務器響應。如果出現錯誤,服務器將引發通道異常(don't wait for a server response. In case of error the server will raise a channel exception)
		*	callback: 回調函數(A PHP Callback)
		*/

		$channel->basic_consume($this->queue, $consumerTag, false, false, false, false, [new FanoutConsumer1(),'process_message']);

		register_shutdown_function([new FanoutConsumer1(),'shutdown'], $channel, $this->connection);

		// 循環,只要通道已註冊回調(Loop as long as the channel has callbacks registered)
		while ($channel->is_consuming()) {
			$channel->wait();
		}

		exit;
	}
	
	/**
	 * 回調函數
	 */
	public function process_message($message){
		echo "\n--------\n";
		echo $message->body;
		echo "\n--------\n";

		$message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

		// 發送字符串“quit”通知消費者退出。(Send a message with the string "quit" to cancel the consumer.)
		if ($message->body === 'quit') {
			$message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
		}
	}
	
	/**
	 * @param \PhpAmqpLib\Channel\AMQPChannel $channel
	 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
	 */
	public function shutdown($channel, $connection)
	{
		$channel->close();
		$connection->close();
	}

}

FanoutConsumer2.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: direct形式---生產者
 */

class DirectProducer extends BasicConnect
{
	public $exchange 	= 'direct_test_exchange';
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$channel = $this->connection->channel();
	   /**
		*	name: $exchange 交換機名稱
		*	type: DIRECT   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::DIRECT, false, false, true);
		
		$messageBody = 'I am a direct message';
		
		$message = new AMQPMessage($messageBody, ['content_type' => 'text/plain']);
		
		$channel->basic_publish($message, $this->exchange, 'direct_key1');
		
		$channel->close();
		
		$this->connection->close();

		exit;
	}
}

DirectProducer.php

https://www.jianshu.com/p/fdb195698a5a

https://my.oschina.net/u/3698467/blog/1825316

 

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: topic形式--消費者1
 * @user: dingling
 * @version: V1.0
 * @date: 20200528
 */

class DirectConsumer1 extends BasicConnect
{
	public $exchange 	= 'direct_test_exchange';
	public $queue 		= 'direct_test_queue1';#注意就這個隊列名不同
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$consumerTag = 'consumer' . getmypid();

		$channel = $this->connection->channel();

	   /**
		*	name: $queue    隊列名稱,在fanout類型的交換機中必須唯一(should be unique in fanout exchange.)
		*	passive: false  不檢查是否存在同名隊列(don't check if a queue with the same name exists)
		*	durable: false  服務器重啓後隊列將無法生存(the queue will not survive server restarts)
		*	exclusive: false 隊列可能被其他通道訪問(the queue might be accessed by other channels)
		*	auto_delete: true 一旦通道關閉,隊列將被刪除(the queue will be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, false, false, true);

	   /**
		*	name: $exchange 交換機名稱
		*	type: DIRECT   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::DIRECT, false, false, true);

		$channel->queue_bind($this->queue, $this->exchange, 'direct_key1');
		
		/*
		*	queue: 隊列名稱,從何處獲取消息的隊列(Queue from where to get the messages)
		*	consumer_tag: 消費者標識符(Consumer identifier)
		*	no_local: 不接收此消費者發佈的消息。(Don't receive messages published by this consumer.)
		*	no_ack: 如果設置爲真,則此用戶將使用自動確認模式(If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.)
		*	exclusive: 請求獨佔使用者訪問,這意味着只有此使用者可以訪問隊列(Request exclusive consumer access, meaning only this consumer can access the queue)
		*	nowait: 不要等待服務器響應。如果出現錯誤,服務器將引發通道異常(don't wait for a server response. In case of error the server will raise a channel exception)
		*	callback: 回調函數(A PHP Callback)
		*/

		$channel->basic_consume($this->queue, $consumerTag, false, false, false, false, [new FanoutConsumer1(),'process_message']);

		register_shutdown_function([new FanoutConsumer1(),'shutdown'], $channel, $this->connection);

		// 循環,只要通道已註冊回調(Loop as long as the channel has callbacks registered)
		while ($channel->is_consuming()) {
			$channel->wait();
		}

		exit;
	}
	
	/**
	 * 回調函數
	 */
	public function process_message($message){
		echo "\n--------\n";
		echo $message->body;
		echo "\n--------\n";

		$message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

		// 發送字符串“quit”通知消費者退出。(Send a message with the string "quit" to cancel the consumer.)
		if ($message->body === 'quit') {
			$message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
		}
	}
	
	/**
	 * @param \PhpAmqpLib\Channel\AMQPChannel $channel
	 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
	 */
	public function shutdown($channel, $connection)
	{
		$channel->close();
		$connection->close();
	}

}

DirectConsumer1.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: topic形式---生產者
 *			注意:
 */

class TopicProducer extends BasicConnect
{
	public $exchange 	= 'topic_test_exchange';
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$channel = $this->connection->channel();
	   /**
		*	name: $exchange 交換機名稱
		*	type: TOPIC   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::TOPIC, false, false, true);
		
		$messageBody = 'I am a TOPIC message';
		
		$message = new AMQPMessage($messageBody, ['content_type' => 'text/plain']);
		
		$res = $channel->basic_publish($message, $this->exchange, 'key.1.2');#routing_key設置爲key.1.2,只有TopicConsumer2{'key.#'}消費者能收到
		#$res = $channel->basic_publish($message, $this->exchange, 'key.1');#routing_key設置爲key.1,TopicConsumer1{'key.*'}和TopicConsumer2{'key.#'}消費者都可以收到
		
		$channel->close();
		
		$this->connection->close();

		exit;
	}
}

TopicProducer.php

*(星號)可以代替一個任意標識符 ;#(井號)可以代替零個或多個標識符。

https://blog.csdn.net/a491857321/article/details/50616323  (JAVA實現)

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: topic形式--消費者1
 */

class TopicConsumer1 extends BasicConnect
{
	public $exchange 	= 'topic_test_exchange';
	public $queue 		= 'topic_test_queue1';#注意就這個隊列名不同
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$consumerTag = 'consumer' . getmypid();

		$channel = $this->connection->channel();

	   /**
		*	name: $queue    隊列名稱,在fanout類型的交換機中必須唯一(should be unique in fanout exchange.)
		*	passive: false  不檢查是否存在同名隊列(don't check if a queue with the same name exists)
		*	durable: false  服務器重啓後隊列將無法生存(the queue will not survive server restarts)
		*	exclusive: false 隊列可能被其他通道訪問(the queue might be accessed by other channels)
		*	auto_delete: true 一旦通道關閉,隊列將被刪除(the queue will be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, false, false, true);

	   /**
		*	name: $exchange 交換機名稱
		*	type: TOPIC   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::TOPIC, false, false, true);

		$channel->queue_bind($this->queue, $this->exchange, 'key.*');

		
		/*
		*	queue: 隊列名稱,從何處獲取消息的隊列(Queue from where to get the messages)
		*	consumer_tag: 消費者標識符(Consumer identifier)
		*	no_local: 不接收此消費者發佈的消息。(Don't receive messages published by this consumer.)
		*	no_ack: 如果設置爲真,則此用戶將使用自動確認模式(If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.)
		*	exclusive: 請求獨佔使用者訪問,這意味着只有此使用者可以訪問隊列(Request exclusive consumer access, meaning only this consumer can access the queue)
		*	nowait: 不要等待服務器響應。如果出現錯誤,服務器將引發通道異常(don't wait for a server response. In case of error the server will raise a channel exception)
		*	callback: 回調函數(A PHP Callback)
		*/

		$channel->basic_consume($this->queue, $consumerTag, false, false, false, false, [new FanoutConsumer1(),'process_message']);

		register_shutdown_function([new FanoutConsumer1(),'shutdown'], $channel, $this->connection);

		// 循環,只要通道已註冊回調(Loop as long as the channel has callbacks registered)
		while ($channel->is_consuming()) {
			$channel->wait();
		}

		exit;
	}
	
	/**
	 * 回調函數
	 */
	public function process_message($message){
		echo "\n--------\n";
		echo $message->body;
		echo "\n--------\n";

		$message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

		// 發送字符串“quit”通知消費者退出。(Send a message with the string "quit" to cancel the consumer.)
		if ($message->body === 'quit') {
			$message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
		}
	}
	
	/**
	 * @param \PhpAmqpLib\Channel\AMQPChannel $channel
	 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
	 */
	public function shutdown($channel, $connection)
	{
		$channel->close();
		$connection->close();
	}

}

TopicConsumer1.php

<?php
namespace app\rabbitmq\controller;
use think\Controller;
use app\rabbitmq\controller\BasicConnect as BasicConnect;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
/**
 * @desc: topic形式--消費者2
 */

class TopicConsumer2 extends BasicConnect
{
	public $exchange 	= 'topic_test_exchange';
	public $queue 		= 'topic_test_queue2';#注意就這個隊列名不同
	
	public function __construct(){
		parent::__construct();
	}
	
	public function Index(){
		$consumerTag = 'consumer' . getmypid();

		$channel = $this->connection->channel();

	   /**
		*	name: $queue    隊列名稱,在fanout類型的交換機中必須唯一(should be unique in fanout exchange.)
		*	passive: false  不檢查是否存在同名隊列(don't check if a queue with the same name exists)
		*	durable: false  服務器重啓後隊列將無法生存(the queue will not survive server restarts)
		*	exclusive: false 隊列可能被其他通道訪問(the queue might be accessed by other channels)
		*	auto_delete: true 一旦通道關閉,隊列將被刪除(the queue will be deleted once the channel is closed.)
		*/
		$channel->queue_declare($this->queue, false, false, false, true);

	   /**
		*	name: $exchange 交換機名稱
		*	type: TOPIC   交換機類型
		*	passive: false 是否檢查存在同名的交換機(don't check is an exchange with the same name exists)
		*	durable: false 服務器重啓後銷燬交換機(the exchange won't survive server restarts)
		*	auto_delete: true 管道(channel)關閉後將銷燬交換機(the exchange will be deleted once the channel is closed.)
		*/
		$channel->exchange_declare($this->exchange, AMQPExchangeType::TOPIC, false, false, true);

		$channel->queue_bind($this->queue, $this->exchange, 'key.#');

		
		/*
		*	queue: 隊列名稱,從何處獲取消息的隊列(Queue from where to get the messages)
		*	consumer_tag: 消費者標識符(Consumer identifier)
		*	no_local: 不接收此消費者發佈的消息。(Don't receive messages published by this consumer.)
		*	no_ack: 如果設置爲真,則此用戶將使用自動確認模式(If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.)
		*	exclusive: 請求獨佔使用者訪問,這意味着只有此使用者可以訪問隊列(Request exclusive consumer access, meaning only this consumer can access the queue)
		*	nowait: 不要等待服務器響應。如果出現錯誤,服務器將引發通道異常(don't wait for a server response. In case of error the server will raise a channel exception)
		*	callback: 回調函數(A PHP Callback)
		*/

		$channel->basic_consume($this->queue, $consumerTag, false, false, false, false, [new FanoutConsumer1(),'process_message']);

		register_shutdown_function([new FanoutConsumer1(),'shutdown'], $channel, $this->connection);

		// 循環,只要通道已註冊回調(Loop as long as the channel has callbacks registered)
		while ($channel->is_consuming()) {
			$channel->wait();
		}

		exit;
	}
	
	/**
	 * 回調函數
	 */
	public function process_message($message){
		echo "\n--------\n";
		echo $message->body;
		echo "\n--------\n";

		$message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

		// 發送字符串“quit”通知消費者退出。(Send a message with the string "quit" to cancel the consumer.)
		if ($message->body === 'quit') {
			$message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
		}
	}
	
	/**
	 * @param \PhpAmqpLib\Channel\AMQPChannel $channel
	 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
	 */
	public function shutdown($channel, $connection)
	{
		$channel->close();
		$connection->close();
	}

}

TopicConsumer2.php

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