【仿RabbitMQ的发布订阅式消息队列】 ---- 功能测试联调

Welcome to 9ilk's Code World

(๑•́ ₃ •̀๑) 个人主页: 9ilk

(๑•́ ₃ •̀๑) 文章专栏: 项目


本篇博客主要是对消息队列项目组件的功能的一个测试,主要测试点在于在不同模式下的交换机,客户端是否能正确收到订阅队列的消息,这里我们测试的是广播交换、直接交换和主题交换。

广播交换模式测试

主要测试方案是:

  • 声明一个交换机,且为广播模式
  • 声明两个队列queue1和queue2,设置好binding_key然后和交换机进行绑定。
  • 前面两个操作,为了以防万一,消费者客户端和生产者客户端都做一遍这个工作。
  • 然后订阅客户端就可以订阅queue1,发布客户端发布的消息,订阅客户端应该都能收到

发布客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <google/protobuf/map.h>
#include <memory>
#include <string>

int main()
{
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);
    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);

    channel->declareQueue("queue2",true,false,false,tmp_map);
    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //5. 循环向交换机发布消息
    for(int i = 0 ; i < 10 ; i++)
    {
        //广播
        channel->basicPublish("exchange1",nullptr,"Hello Queue-"+to_string(i));
    }
    //6.关闭信道
    conn->closeChannel(channel);
    return 0;
}

订阅客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <functional>
#include <google/protobuf/map.h>
#include <memory>
#include<thread>
#include <string>
#include<iostream>
#include "../mqcommon/logger.hpp"
using namespace std;

void callBack(zmq::Channel::ptr channel,const string& tag,const zmq::BasicProperties* bp,const string& body)
{
   cout << tag << "消费了消息:" << body << endl;
   //应答
   channel->basicAck(bp->id());
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        DBG_LOG("Usage: ./consume_client queue_anme");
        exit(1);
    }
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);

    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);
    channel->declareQueue("queue2",true,false,false,tmp_map);

    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //6.订阅队列消息
    auto functor = std::bind(callBack,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    channel->basicConsume("consumer1",argv[1],false,functor);
    //7.关闭信道
    while(1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    conn->closeChannel(channel);
 
    return 0;
}

直接交换模式测试

主要测试方案:

  • 同样声明一个交换机和两个队列,交换机是直接交换模式
  • 直接交换模式下,直接比较routing_key和binding_key是否相同
  • 我们将消息设置为跟queue2的binding_key相同
  • 因此分别启动两个订阅客户端分别订阅queue1、queue2,发布客户端发布消息之后应该是只有订阅了queue2的客户端能收到消息。

发布客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <google/protobuf/map.h>
#include <memory>
#include <string>

int main()
{
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为直接模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::DIRECT,true,false,tmp_map);
    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);

    channel->declareQueue("queue2",true,false,false,tmp_map);
    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //5. 循环向交换机发布消息
    for(int i = 0 ; i < 10 ; i++)
    {
        //直接
        zmq::BasicProperties bp;
        bp.set_id(zmq::uuidHelper::uuid());
        bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
        bp.set_routing_key("news.music.#");
        channel->basicPublish("exchange1",&bp,"Hello Queue-"+to_string(i));
    }

    //6.关闭信道
    conn->closeChannel(channel);
    return 0;
}

消费客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <functional>
#include <google/protobuf/map.h>
#include <memory>
#include<thread>
#include <string>
#include<iostream>
#include "../mqcommon/logger.hpp"
using namespace std;

void callBack(zmq::Channel::ptr channel,const string& tag,const zmq::BasicProperties* bp,const string& body)
{
   cout << tag << "消费了消息:" << body << endl;
   //应答
   channel->basicAck(bp->id());
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        DBG_LOG("Usage: ./consume_client queue_anme");
        exit(1);
    }
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);

    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);
    channel->declareQueue("queue2",true,false,false,tmp_map);

    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //6.订阅队列消息
    auto functor = std::bind(callBack,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    channel->basicConsume("consumer1",argv[1],false,functor);
    //7.关闭信道
    while(1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    conn->closeChannel(channel);
 
    return 0;
}

主题交换模式测试

  • 发布三种routing_key消息,分别是news.music.queue、news.music.pop、news.sport
  • 因此订阅queue1的收不到任何消息,订阅queue2的只能收到前两种

发布客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <google/protobuf/map.h>
#include <memory>
#include <string>

int main()
{
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);
    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);

    channel->declareQueue("queue2",true,false,false,tmp_map);
    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //5. 循环向交换机发布消息
    for(int i = 0 ; i < 10 ; i++)
    {
        //直接
        zmq::BasicProperties bp;
        bp.set_id(zmq::uuidHelper::uuid());
        bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
        bp.set_routing_key("news.music.queue");
        channel->basicPublish("exchange1",&bp,"Hello Queue-"+to_string(i));
    }
    zmq::BasicProperties bp;
    bp.set_id(zmq::uuidHelper::uuid());
    bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
    bp.set_routing_key("news.music.pop");
    channel->basicPublish("exchange1",&bp,"Hello pop");

    bp.set_id(zmq::uuidHelper::uuid());
    bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
    bp.set_routing_key("news.sport");
    channel->basicPublish("exchange1",&bp,"Hello sport");
    //6.关闭信道
    conn->closeChannel(channel);
    return 0;
}

消费客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <functional>
#include <google/protobuf/map.h>
#include <memory>
#include<thread>
#include <string>
#include<iostream>
#include "../mqcommon/logger.hpp"
using namespace std;

void callBack(zmq::Channel::ptr channel,const string& tag,const zmq::BasicProperties* bp,const string& body)
{
   cout << tag << "消费了消息:" << body << endl;
   //应答
   channel->basicAck(bp->id());
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        DBG_LOG("Usage: ./consume_client queue_anme");
        exit(1);
    }
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::TOPIC,true,false,tmp_map);

    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);
    channel->declareQueue("queue2",true,false,false,tmp_map);

    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //6.订阅队列消息
    auto functor = std::bind(callBack,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    channel->basicConsume("consumer1",argv[1],false,functor);
    //7.关闭信道
    while(1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    conn->closeChannel(channel);
 
    return 0;
}
相关推荐
肆忆_4 小时前
# 用 5 个问题学懂 C++ 虚函数(入门级)
c++
chlk1237 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑7 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件8 小时前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
不想写代码的星星8 小时前
虚函数表:C++ 多态背后的那个男人
c++
深紫色的三北六号17 小时前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash21 小时前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
初次攀爬者1 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
哈基咪怎么可能是AI1 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行2 天前
Linux和window共享文件夹
linux