【RabbitMQ】php语言对RabbitMQ四种工作模式的基础实现

学习资料:
1.黑马程序员RabbitMQ全套教程
2.RabbitMQ的PHP教程之入门

1.RabbitMQ结构:

2. WORK QUEUES 工作队列 模式:

生产者代码:
<?php
/**
 * "Work Queues"工作模式--生产者
 */
$conConfig = [
    'host' => '',//安装了rabbitMQ的主机ip
    'port' => '5672',//端口号
    'login' => 'guest',//登录账号
    'password' => 'guest',//登录密码
];

$e_name = "exchange_one";//交换器名称

try {
    //创建一个MQ连接实例并执行连接操作
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }

    //根据连接,新建通道
    $channel = new AMQPChannel($connection);

    //定义交换器属性并声明交换器
    $exchange = new AMQPExchange($channel);
    $exchange->setName($e_name);//设置交换器名称
    $exchange->setType( AMQP_EX_TYPE_DIRECT); //设置交换器类型
    $exchange->setFlags(AMQP_DURABLE);//持久交换器,在broker重启后交换器不会消失,一般常使用该选项
    $exchange->declareExchange();//声明交换器

    for ($i = 0; $i < 100; $i++) {
        $message = '交换器消息--' . $i;

        //发送消息到MQ
        $state = $exchange->publish($message);

        if ($state) {
            echo 'success' . $i . PHP_EOL;
        } else {
            echo 'fail' . PHP_EOL;
        }
    }
    //关闭通道和连接
    $channel->close();
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}

消费者代码:
  1. 同一时间在一个终端运行此脚本就是类似helloworld模式,
  2. 同一时间在n个终端运行此脚本则等于有n个消费者在一起消费队列里的消息,且消费者之间为竞争关系。
<?php
/**
 * "Work Queues"工作模式--消费者
 */

$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_one";
$queueName = "queues_1";

try {
    //创建连接
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }
    //新建通道
    $channel = new AMQPChannel($connection);

    //创建队列
    $queue = new AMQPQueue($channel);
    $queue->setName($queueName);
    $queue->setFlags(AMQP_DURABLE);
    $queue->declareQueue();
    $queue->bind($e_name);//将队列和交换器绑定关系


    var_dump("Waiting for message...");

    // 消费队列中的消息
    //consume函数的第二个参数如果为AMQP_AUTOACK,则当消费者接收到消息后向rabbitmq自动确认消息接收成功,
    //如果第二个参数为空,则需要我们在代码中调用ack方法来确认消息接收状态(看匿名回调函数的最后一句就是)
    while (TRUE) {
        $queue->consume(function ($envelope, $queue) {
            $msg = $envelope->getBody();
            var_dump($msg);
            $queue->ack($envelope->getDeliveryTag()); // 手动发送ACK应答
        });
    }

    // 断开连接
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}
运行结果:

生产者脚本运行结果:

success0
success1
success2
success3
success4
success5
success6
success7
success8
success9

消费者1监听结果:

string(22) "Waiting for message..."
string(18) "交换器消息--0"
string(18) "交换器消息--2"
string(18) "交换器消息--4"
string(18) "交换器消息--6"
string(18) "交换器消息--7"
string(18) "交换器消息--9"

消费者2监听结果:

string(22) "Waiting for message..."
string(18) "交换器消息--1"
string(18) "交换器消息--3"
string(18) "交换器消息--5"
string(18) "交换器消息--8"

3.PUBLISH/SUBSCRIBE 广播订阅模式

生产者代码:
  1. 改变交换器的类型为AMQP_EX_TYPE_FANOUT
  2. 删除创建队列的代码
<?php
/**
 * "Publish/Subscribe"工作模式--生产者
 */
$conConfig = [
    'host' => '',//安装了rabbitMQ的主机ip
    'port' => '5672',//端口号
    'login' => 'guest',//登录账号
    'password' => 'guest',//登录密码
];

$e_name = "exchange_two";//交换器名称

try {
    //创建一个MQ连接实例并执行连接操作
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }

    //根据连接,新建通道
    $channel = new AMQPChannel($connection);

    //定义交换器属性并声明交换器
    $exchange = new AMQPExchange($channel);
    $exchange->setName($e_name);//设置交换器名称
    $exchange->setType( AMQP_EX_TYPE_FANOUT); //设置交换器类型
    $exchange->setFlags(AMQP_DURABLE);//持久交换器,在broker重启后交换器不会消失,一般常使用该选项
    $exchange->declareExchange();//声明交换器

    for ($i = 0; $i < 5; $i++) {
        $message = '交换器消息--' . $i;

        //发送消息到MQ交换器,成功返回true,失败返回false
        $state = $exchange->publish($message);

        if ($state) {
            echo 'success' . $i . PHP_EOL;
        } else {
            echo 'fail' . PHP_EOL;
        }
    }
    //关闭通道和连接
    $channel->close();
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}
消费者代码:
  1. 可以有一个或多个消费者,消费者们之间主要区别就是$queueName队列名称的值不一样。

  2. 如果同一时间,两个终端运行两个不同消费者脚本,那么两个消费者消费的消息一致。

    如果同一时间,两个终端运行同一个消费者脚本,那依旧是work queues那种竞争关系。

cus1.php:

<?php
/**
 * "Publish/Subscribe"工作模式--消费者
 */

$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_two";
$queueName = "queues_2";

try {
    //创建连接
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }
    //新建通道
    $channel = new AMQPChannel($connection);

    //创建队列
    $queue = new AMQPQueue($channel);
    $queue->setName($queueName);
    $queue->setFlags(AMQP_DURABLE);
    $queue->declareQueue();
    $queue->bind($e_name);//将队列和交换器绑定关系


    var_dump("Waiting for message...");

    while (TRUE) {
        $queue->consume(function ($envelope, $queue) {
            $msg = $envelope->getBody();
            var_dump($msg);
            $queue->ack($envelope->getDeliveryTag()); // 手动发送ACK应答
        });
    }

    // 断开连接
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}

cus2.php:

<?php
/**
 * "Publish/Subscribe"工作模式--消费者
 */

$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_two";
$queueName = "queues_3";
//后面内容和cus1.php一致。。。
运行结果:

生产者脚本:

success0
success1
success2
success3
success4

消费者1/消费者2(所有消费者的监听结果都将一致):

string(22) "Waiting for message..."
string(18) "交换器消息--0"
string(18) "交换器消息--1"
string(18) "交换器消息--2"
string(18) "交换器消息--3"
string(18) "交换器消息--4"

4.ROUITING 路由模式

生产者代码:

改变交换器的类型为AMQP_EX_TYPE_DIRECT

<?php
/**
 * "Routing"工作模式--生产者
 */
$conConfig = [
    'host' => '',//安装了rabbitMQ的主机ip
    'port' => '5672',//端口号
    'login' => 'guest',//登录账号
    'password' => 'guest',//登录密码
];

$e_name = "exchange_three";//交换器名称
$arr =[
    'notice' =>'[notice]类消息内容1',//本消息的路由=>本消息的内容
    'warning' =>'[warning]类消息内容1',
    'error' =>'[error]类消息内容1'
];


try {
    //创建一个MQ连接实例并执行连接操作
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }

    //根据连接,新建通道
    $channel = new AMQPChannel($connection);

    //定义交换器属性并声明交换器
    $exchange = new AMQPExchange($channel);
    $exchange->setName($e_name);//设置交换器名称
    $exchange->setType( AMQP_EX_TYPE_DIRECT); //设置交换器类型
    $exchange->setFlags(AMQP_DURABLE);//持久交换器,在broker重启后交换器不会消失,一般常使用该选项
    $exchange->declareExchange();//声明交换器

    foreach ($arr as $typeName=>$typeMsg) {

        //发送消息到MQ,为消息指定路由,成功返回true,失败返回false
        $state = $exchange->publish($typeMsg,$typeName);

        if ($state) {
            echo 'success:' . $typeName . PHP_EOL;
        } else {
            echo 'fail:' . PHP_EOL;
        }
    }
    //关闭通道和连接
    $channel->close();
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}
消费者代码:

cus1.php:

如果消息的指定路由key为noticewarning,则交换器会分发到此队列queues_4

<?php
/**
 * "Routing"工作模式--消费者
 */
$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_three";
$queueName = "queues_4";
$routingKey1 = "notice";
$routingKey2 = "warning";

try {
    //创建连接
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }
    //新建通道
    $channel = new AMQPChannel($connection);

    //创建队列
    $queue = new AMQPQueue($channel);
    $queue->setName($queueName);
    $queue->setFlags(AMQP_DURABLE);
    $queue->declareQueue();
    $queue->bind($e_name,$routingKey1);
    $queue->bind($e_name,$routingKey2);
    var_dump("Waiting for message...");

    while (TRUE) {
        $queue->consume(function ($envelope, $queue) {
            $msg = $envelope->getBody();
            var_dump($msg);
            $queue->ack($envelope->getDeliveryTag()); // 手动发送ACK应答
        });
    }

    // 断开连接
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}

cus2.php:

如果消息的指定路由key为noticewarning,则交换器会分发到此队列queues_4

<?php
/**
 * "Routing"工作模式--消费者
 */
$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_three";
$queueName = "queues_4";
$routingKey1 = "error";
$routingKey2 = "warning";
//后面内容和消费者1一致。。。

运行结果:

生产者代码运行结果:

success:notice
success:warning
success:error

cus1.php运行结果:

string(24) "[notice]类消息内容1"
string(25) "[warning]类消息内容1"

cus2.php运行结果:

string(25) "[warning]类消息内容1"
string(23) "[error]类消息内容1"

5.TOPICS 模糊匹配模式

*(星号)可以代表一个单词
#(井号)可以代表零个或n个单词

单词和单词之间最好用.隔开

生产者代码:

改变交换器的类型为AMQP_EX_TYPE_TOPIC

<?php
/**
 * "Topics"模糊匹配模式--生产者
 */
$conConfig = [
    'host' => '',//安装了rabbitMQ的主机ip
    'port' => '5672',//端口号
    'login' => 'guest',//登录账号
    'password' => 'guest',//登录密码
];

$e_name = "exchange_five";//交换器名称

//*(星号)可以代表一个单词
//#(井号)可以代表零个或n个单词

$arr =[
    'notice' =>'notice',//本消息的路由=>本消息的内容
    'warning' =>'warning',
    'error' =>'error',

    'notice.word' =>'--notice.word',
    'warning.word' =>'--warning.word',
    'error.word' =>'--error.word',

    'notice.word.word' =>'------notice.word.word',
    'warning.word.word' =>'------warning.word.word',
    'error.word.word' =>'------error.word.word',

];


try {
    //创建一个MQ连接实例并执行连接操作
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }

    //根据连接,新建通道
    $channel = new AMQPChannel($connection);

    //定义交换器属性并声明交换器
    $exchange = new AMQPExchange($channel);
    $exchange->setName($e_name);//设置交换器名称
    $exchange->setType( AMQP_EX_TYPE_TOPIC); //设置交换器类型
    $exchange->setFlags(AMQP_DURABLE);//持久交换器,在broker重启后交换器不会消失,一般常使用该选项
    $exchange->declareExchange();//声明交换器

    foreach ($arr as $typeName=>$typeMsg) {

        //发送消息到MQ,为消息指定路由,成功返回true,失败返回false
        $state = $exchange->publish($typeMsg,$typeName);

        if ($state) {
            echo 'success:' . $typeName . PHP_EOL;
        } else {
            echo 'fail:' . PHP_EOL;
        }
    }
    //关闭通道和连接
    $channel->close();
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}
消费者代码:

cus1.php:

<?php
/**
 * "Topics"模糊匹配模式--消费者
 */
$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_five";
$queueName = "queues_6";

$routingKey1 = "notice.*";
$routingKey2 = "warning.*";
$routingKey3 = "error.*";

try {
    //创建连接
    $connection = new AMQPConnection($conConfig);
    $connection->connect();
    if (!$connection->isConnected()) {
        echo 'rabbitmq connect fail';
        die();
    }
    //新建通道
    $channel = new AMQPChannel($connection);

    //创建队列
    $queue = new AMQPQueue($channel);
    $queue->setName($queueName);
    $queue->setFlags(AMQP_DURABLE);
    $queue->declareQueue();

    $queue->bind($e_name,$routingKey1);
    $queue->bind($e_name,$routingKey2);
    $queue->bind($e_name,$routingKey3);

    var_dump("Waiting for message...");

    while (TRUE) {
        $queue->consume(function ($envelope, $queue) {
            $msg = $envelope->getBody();
            var_dump($msg);
            $queue->ack($envelope->getDeliveryTag()); // 手动发送ACK应答
        });
    }

    // 断开连接
    $connection->disconnect();

} catch (AMQPConnectionException $e) {
    var_dump($e);
    exit();
}

cus2.php:

<?php
/**
 * "Topics"模糊匹配模式--消费者
 */
$conConfig = [
    'host' => '',
    'port' => '5672',
    'login' => 'guest',
    'password' => 'guest',
];

$e_name = "exchange_five";
$queueName = "queues_7";

$routingKey1 = "notice.#";
$routingKey2 = "warning.#";
$routingKey3 = "error.#";

//以下内容和cus1.php一致
运行结果:

生产者运行脚本:

success:notice
success:warning
success:error
success:notice.word
success:warning.word
success:error.word
success:notice.word.word
success:warning.word.word
success:error.word.word

消费者cus1监听结果:

string(22) "Waiting for message..."
string(13) "--notice.word"
string(14) "--warning.word"
string(12) "--error.word"

消费者cus2监听结果:

string(22) "Waiting for message..."
string(6) "notice"
string(7) "warning"
string(5) "error"
string(13) "--notice.word"
string(14) "--warning.word"
string(12) "--error.word"
string(22) "------notice.word.word"
string(23) "------warning.word.word"
string(21) "------error.word.word"
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值