第十七章:联调测试

目录

第一节:生产者客户端

第二节:消费者客户端

第三节:启动服务器

第四节:联调测试

        1-1.发送/推送消息测试

下期预告:


第一节:生产者客户端

        在mqclient创建一个publish.cc的文件,并添加以下内容:

#include "mq_connection.hpp"
#include "../mqcommon/mq_msg.pb.h"
int main()
{
    // 实例化异步工作对象
    zd::LoopWorker::ptr worker = std::make_shared();
    // 实例化连接对象
    zd::MqConnection conn("127.0.0.1",8085,worker);
    conn.connect();
    // 创建一个信道(客户端)
    zd::Channel::ptr channel = conn.openChannel();  

    // 发布消息
    for(int i = 0;i < 10;i++)
    {
        zd::BasicProperties bp;
        bp.set_id(zd::UUIDHelper::uuid());
        bp.set_delivery_mode(zd::DeliveryMode::DURABLE);
        bp.set_routing_key("news.music.pop");
        channel->basicPublish("e1",&bp,"Hello World-"+std::to_string(i));
    }

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

        这个客户端向e1交换机发送了10条持久化消息,内容是"Hello World-i",routing_key都是"news.music.pop"。        

第二节:消费者客户端

        在mqclient创建一个consume1.cc的文件,并添加以下内容:

#include "mq_connection.hpp"
#include "../mqcommon/mq_msg.pb.h"

// 消费者的消息处理函数
void callback(const zd::Channel::ptr& channel,const std::string& ctag,const zd::BasicProperties* bp,const std::string& body)
{
    channel->basicAck(bp->id()); // 确认消息确实收到了
    LOG("%s 消费了消息:%s",ctag.c_str(),body.c_str());   
}

int main(int argc,char** argv)
{ 
    // 实例化异步工作对象 
    zd::LoopWorker::ptr worker = std::make_shared(); 
    // 实例化连接对象
    zd::MqConnection::ptr conn = std::make_shared("1.14.198.29",8085,worker);
    conn->connect();
    // 创建一个信道(客户端)
    zd::Channel::ptr channel = conn->openChannel(); 

    // 1.通过信道声明一个交换机"e1"
    google::protobuf::Map map;
    channel->declareExchange("e1",zd::ExchangeType::TOPIC,true,false,map);
        // 2.声明两个队列 
    channel->declareMsgQueue("q1",true,false,false,map); 
    channel->declareMsgQueue("q2",true,false,false,map);
        // 3.绑定两个队列  
    channel->bind("e1","q1","queue1");
    channel->bind("e1","q2","news.music.#");
    
    auto func = std::bind(callback,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    // 订阅队列
    if(channel->basicConsume("q1","消费者-1",false,func) == false)
    {
        LOG("订阅失败队列 %s 失败","q1");
    }
    // 等待消息推送
    while(true)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    // 关闭信道
    conn->closeChannel(channel);
    return 0;
}

        它创建了交换机"e1",两个队列"q1"、"q2",将它们绑定起来并且设置了不同的binding_key。

        并且绑定了"q1"。

        根据生产者发送的消息的routing_key,只有"q2"可以匹配成功。

        在mqclient创建一个consume2.cc的文件,并添加以下内容:

#include "mq_connection.hpp"
#include "../mqcommon/mq_msg.pb.h"

void callback(const zd::Channel::ptr& channel,const std::string& ctag,const zd::BasicProperties* bp,const std::string& body)
{
    channel->basicAck(bp->id());
    LOG("%s 消费了消息:%s",ctag.c_str(),body.c_str());
    
}

int main(int argc,char** argv)
{ 
    // 实例化异步工作对象 
    zd::LoopWorker::ptr worker = std::make_shared(); 
    // 实例化连接对象
    zd::MqConnection::ptr conn = std::make_shared("1.14.198.29",8085,worker);
    conn->connect();
    // 创建一个信道(客户端)
    zd::Channel::ptr channel = conn->openChannel(); 
    
    auto func = std::bind(callback,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    // 订阅队列
    if(channel->basicConsume("q2","消费者-2",false,func) == false)
    {
        LOG("订阅失败队列 %s 失败","q2");
    }
    // 等待消息推送
    while(true)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    // 关闭信道
    conn->closeChannel(channel);
    return 0;
}

        它订阅了"q2"队列。

        编译上述3个客户端:

all:publish consume2 consume1

publish:publish.cc ../mqcommon/mq_msg.pb.cc ../mqcommon/mq_proto.pb.cc ../mqthird/include/muduo/proto/codec.cc
	g++ -std=c++14 $^ -o $@ -lprotobuf -pthread -lmuduo_net -lmuduo_base -lz -L../mqthird/lib -I../mqthird/include

consume1:consume1.cc ../mqcommon/mq_msg.pb.cc ../mqcommon/mq_proto.pb.cc ../mqthird/include/muduo/proto/codec.cc
	g++ -std=c++14 $^ -o $@ -lprotobuf -pthread -lmuduo_net -lmuduo_base -lz -L../mqthird/lib -I../mqthird/include

consume2:consume2.cc ../mqcommon/mq_msg.pb.cc ../mqcommon/mq_proto.pb.cc ../mqthird/include/muduo/proto/codec.cc
	g++ -std=c++14 $^ -o $@ -lprotobuf -pthread -lmuduo_net -lmuduo_base -lz -L../mqthird/lib -I../mqthird/include

第三节:启动服务器

        在mserver目录下创建server.cc,打开并添加以下内容:

#include "mq_server.hpp"
int main()
{
    zd::MqServer server(8085,"host1","./data/host1/");
    server.start();   
    return 0;   
}         

        它的功能是启动服务器,并且所有的持久化数据都保存在"./data/host1/"路径下。

        编译服务器:

server:server.cc mq_server.cc ../mqcommon/mq_proto.pb.cc ../mqcommon/mq_msg.pb.cc ../mqthird/include/muduo/proto/codec.cc
	g++ -g -std=c++14 $^ -o $@ -lgtest -lprotobuf -lsqlite3 -pthread -lmuduo_net -lmuduo_base -lz -I../mqthird/include -L../mqthird/lib

 

第四节:联调测试

        1-1.发送/推送消息测试

        创建4个会话。

        按照server、consume1、consume2、publish的顺序依次启动,consume1一定要先启动,因为交换机、队列、绑定的声明都由它完成。

        启动完毕后,执行consume2的会话应该消费了消息:

                ​​​​​​​        第十七章:联调测试_第1张图片

        而consume1无任何变化,因为"q1"没有收到任何消息,这是符合预期的。

         然后重启服务器:

        ​​​​​​​        第十七章:联调测试_第2张图片

        这些消息已经被consume2消费过了,所以是无效消息,能加载到说明服务器的历史消息拉取也是正常的。

        最后查看data目录的文件:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        第十七章:联调测试_第3张图片 

        保存sqlite数据库文件meta.bd,队列自己的消息文件都是正常创建的。

        其他的功能可以自己去测试,只需要稍微修改客户端即可。

下期预告:

        至此一个简单的消息队列已经完成了,但是还有一些小功能可以实现,比如队列的独占标志:一个队列只能有一个消费者;

        自动删除标志:交换机没有任何绑定的时候自动删除,队列没有任何绑定和消费者时的自动删除等

        还有队列的订阅模式:每个订阅者都能得到一份消息,而不是只有一个订阅者。

你可能感兴趣的:(仿Rabbit消息队列,C++,c++,消息队列)