rabbitmq的实现(PHP--简单模式、fanout模式、direct模式、topic模式)

5 篇文章 0 订阅
<?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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
RabbitMQ是一个消息队列,提供了六种消息模式,分别是简单模式、工作队列模式、订阅模式、路由模式、主题模式和RPC模式。下面是C#实现这六种模式的代码示例: ### 简单模式 ```csharp using RabbitMQ.Client; using System; using System.Text; class Program { static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null); string message = "Hello World!"; var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body); Console.WriteLine(" [x] Sent {0}", message); } Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } ``` ### 工作队列模式 ```csharp using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text; using System.Threading; class Program { static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare(queue: "task_queue", durable: true, exclusive: false, autoDelete: false, arguments: null); channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false); Console.WriteLine(" [*] Waiting for messages."); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); Console.WriteLine(" [x] Received {0}", message); int dots = message.Split('.').Length - 1; Thread.Sleep(dots * 1000); Console.WriteLine(" [x] Done"); channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); }; channel.BasicConsume(queue: "task_queue", autoAck: false, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } ``` ### 订阅模式 ```csharp using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text; class Program { static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout); var queueName = channel.QueueDeclare().QueueName; channel.QueueBind(queue: queueName, exchange: "logs", routingKey: ""); Console.WriteLine(" [*] Waiting for logs."); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); Console.WriteLine(" [x] {0}", message); }; channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } ``` ### 路由模式 ```csharp using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text; class Program { static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct); var queueName = channel.QueueDeclare().QueueName; if (args.Length < 1) { Console.Error.WriteLine("Usage: {0} [info] [warning] [error]", Environment.GetCommandLineArgs()[0]); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); Environment.ExitCode = 1; return; } foreach (var severity in args) { channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: severity); } Console.WriteLine(" [*] Waiting for messages."); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); var routingKey = ea.RoutingKey; Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message); }; channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } ``` ### 主题模式 ```csharp using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text; class Program { static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "topic_logs", type: ExchangeType.Topic); var queueName = channel.QueueDeclare().QueueName; if (args.Length < 1) { Console.Error.WriteLine("Usage: {0} [binding_key...]", Environment.GetCommandLineArgs()[0]); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); Environment.ExitCode = 1; return; } foreach (var bindingKey in args) { channel.QueueBind(queue: queueName, exchange: "topic_logs", routingKey: bindingKey); } Console.WriteLine(" [*] Waiting for messages."); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); var routingKey = ea.RoutingKey; Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message); }; channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } ``` ### RPC模式 ```csharp using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text; class RPCClient { private readonly IConnection connection; private readonly IModel channel; private readonly string replyQueueName; private readonly EventingBasicConsumer consumer; private readonly IBasicProperties props; public RPCClient() { var factory = new ConnectionFactory() { HostName = "localhost" }; connection = factory.CreateConnection(); channel = connection.CreateModel(); replyQueueName = channel.QueueDeclare().QueueName; consumer = new EventingBasicConsumer(channel); props = channel.CreateBasicProperties(); var correlationId = Guid.NewGuid().ToString(); props.CorrelationId = correlationId; props.ReplyTo = replyQueueName; consumer.Received += (model, ea) => { var body = ea.Body; var response = Encoding.UTF8.GetString(body); if (ea.BasicProperties.CorrelationId == correlationId) { Console.WriteLine(" [.] Got {0}", response); } }; } public string Call(string message) { var messageBytes = Encoding.UTF8.GetBytes(message); channel.BasicPublish( exchange: "", routingKey: "rpc_queue", basicProperties: props, body: messageBytes); channel.BasicConsume( consumer: consumer, queue: replyQueueName, autoAck: true); return ""; } public void Close() { connection.Close(); } } class Program { static void Main(string[] args) { var rpcClient = new RPCClient(); Console.WriteLine(" [x] Requesting fib(30)"); var response = rpcClient.Call("30"); Console.WriteLine(" [.] Got '{0}'", response); rpcClient.Close(); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扬子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值