仿RabbitMQ实现消息队列服务端(二)

文章目录

⽹络通信协议设计

其中⽣产者和消费者都是客⼾端,它们都需要通过⽹络和BrokerServer进⾏通信。具体通信的过程我们使⽤Muduo库来实现,使⽤TCP作为通信的底层协议,同时在这个基础上⾃定义应⽤层协议,完成客⼾端对服务器功能的远端调⽤。我们要实现的远端调⽤接⼝包括:

使⽤⼆进制的⽅式设计应⽤层协议。因为MQMessage的消息体是使⽤Protobuf进⾏序列化的,本⾝是按照⼆进制存储的,所以不太适合⽤json等⽂本格式来定义协议。

下⾯我们设计⼀下应⽤层协议:请求/响应报⽂设计

  • len:4个字节,表⽰整个报⽂的⻓度
  • nameLen:4个字节,表⽰typeName数组的⻓度
  • typeName:是个字节数组,占nameLen个字节,表⽰请求/响应报⽂的类型名,作⽤是分发不同消息到对应的远端接⼝调⽤中
  • protobufData:是个字节数组,占len-nameLen-8个字节,表⽰请求/响应参数数据通过protobuf序列化之后的⼆进制
  • checkSum:4个字节,表⽰整个消息的校验和,作⽤是为了校验请求/响应报⽂的完整性

⼀个创建交换机的请求,如下图⽰:

信道管理模块

在AMQP模型中,除了通信连接Connection概念外,还有⼀个Channel的概念,Channel是针对Connection连接的⼀个更细粒度的通信信道,多个Channel可以使⽤同⼀个通信连接Connection进⾏通信,但是同⼀个Connection的Channel之间相互独⽴。

⽽信道模块就是再次将上述模块进⾏整合提供服务的模块

proto.proto

cpp 复制代码
syntax = "proto3";
package nzq;

import "msg.proto";

//信道的打开与关闭
message openChannelRequest{
    string rid = 1;
    string cid = 2;
};
message closeChannelRequest{
    string rid = 1;
    string cid = 2;
};
//交换机的声明与删除
message declareExchangeRequest{
    string rid = 1;
    string cid = 2;
    string exchange_name = 3;
    ExchangeType exchange_type = 4;
    bool durable = 5;
    bool auto_delete = 6;
    map<string, string> args = 7;
};
message deleteExchangeRequest{
    string rid = 1;
    string cid = 2;
    string exchange_name = 3;
};
//队列的声明与删除
message declareQueueRequest{
    string rid = 1;
    string cid = 2;
    string queue_name = 3;
    bool exclusive = 4;
    bool durable = 5;
    bool auto_delete = 6;
    map<string, string> args = 7;
};
message deleteQueueRequest{
    string rid = 1;
    string cid = 2;
    string queue_name = 3;
};
//队列的绑定与解除绑定
message queueBindRequest{
    string rid = 1;
    string cid = 2;
    string exchange_name = 3;
    string queue_name = 4;
    string binding_key = 5;
};
message queueUnBindRequest{
    string rid = 1;
    string cid = 2;
    string exchange_name = 3;
    string queue_name = 4;
};
//消息的发布
message basicPublishRequest {
    string rid = 1;
    string cid = 2;
    string exchange_name = 3;
    string body = 4;
    BasicProperties properties = 5;
};
//消息的确认
message basicAckRequest {
    string rid = 1;
    string cid = 2;
    string queue_name = 3;
    string message_id = 4;
};
//队列的订阅
message basicConsumeRequest {
    string rid = 1;
    string cid = 2;
    string consumer_tag  =3;
    string queue_name = 4;
    bool auto_ack = 5;
};
//订阅的取消
message basicCancelRequest {
    string rid = 1;
    string cid = 2;
    string consumer_tag = 3;
    string queue_name = 4;
};
//消息的推送
message basicConsumeResponse {
    string cid = 1;
    string consumer_tag = 2;
    string body = 3;
    BasicProperties properties = 4;
};
//通用响应
message basicCommonResponse {
    string rid = 1;
    string cid = 2;
    bool ok = 3;
}
  1. 管理信息:
  • a. 信道ID:信道的唯⼀标识
  • b. 信道关联的消费者:⽤于消费者信道在关闭的时候取消订阅,删除订阅者信息
  • c. 信道关联的连接:⽤于向客⼾端发送数据(响应,推送的消息)
  • d. protobuf协议处理句柄:⽹络通信前的协议处理
  • e. 消费者管理句柄:信道关闭/取消订阅的时候,通过句柄删除订阅者信息
  • f. 虚拟机句柄:交换机/队列/绑定/消息数据管理
  • g. ⼯作线程池句柄(⼀条消息被发布到队列后,需要将消息推送给订阅了对应队列的消费者,过
    程由线程池完成)
  1. 管理操作:
  • a. 提供声明&删除交换机操作(删除交换机的同时删除交换机关联的绑定信息)
  • b. 提供声明&删除队列操作(删除队列的同时,删除队列关联的绑定信息,消息,消费者信息)
  • c. 提供绑定&解绑队列操作
  • d. 提供订阅&取消订阅队列消息操作
  • e. 提供发布&确认消息操作
cpp 复制代码
    using ProtobufCodecPtr = std::shared_ptr<ProtobufCodec>;
    using openChannelRequestPtr = std::shared_ptr<openChannelRequest>;
    using closeChannelRequestPtr = std::shared_ptr<closeChannelRequest>;
    using declareExchangeRequestPtr = std::shared_ptr<declareExchangeRequest>;
    using deleteExchangeRequestPtr = std::shared_ptr<deleteExchangeRequest>;
    using declareQueueRequestPtr = std::shared_ptr<declareQueueRequest>;
    using deleteQueueRequestPtr = std::shared_ptr<deleteQueueRequest>;
    using queueBindRequestPtr = std::shared_ptr<queueBindRequest>;
    using queueUnBindRequestPtr = std::shared_ptr<queueUnBindRequest>;
    using basicPublishRequestPtr = std::shared_ptr<basicPublishRequest>;
    using basicAckRequestPtr = std::shared_ptr<basicAckRequest>;
    using basicConsumeRequestPtr = std::shared_ptr<basicConsumeRequest>;
    using basicCancelRequestPtr = std::shared_ptr<basicCancelRequest>;
    class Channel {
        public:
            using ptr = std::shared_ptr<Channel>;
            Channel(const std::string &id, 
                const VirtualHost::ptr &host, 
                const ConsumerManager::ptr &cmp, 
                const ProtobufCodecPtr &codec, 
                const muduo::net::TcpConnectionPtr &conn,
                const threadpool::ptr &pool):
                _cid(id),
                _conn(conn),
                _codec(codec),
                _cmp(cmp),
                _host(host),
                _pool(pool){
                DLOG("new Channel: %p", this);
            }
            ~Channel() {
                if (_consumer.get() != nullptr) {
                    _cmp->remove(_consumer->tag, _consumer->qname);
                }
                DLOG("del Channel: %p", this);
            }
            //交换机的声明与删除
            void declareExchange(const declareExchangeRequestPtr &req) {
                bool ret = _host->declareExchange(req->exchange_name(), 
                    req->exchange_type(), req->durable(), 
                    req->auto_delete(), req->args());
                return basicResponse(ret, req->rid(), req->cid());
            }
            void deleteExchange(const deleteExchangeRequestPtr &req) {
                _host->deleteExchange(req->exchange_name());
                return basicResponse(true, req->rid(), req->cid());
            }
            //队列的声明与删除
            void declareQueue(const declareQueueRequestPtr &req) {
                bool ret = _host->declareQueue(req->queue_name(),
                    req->durable(), req->exclusive(),
                    req->auto_delete(), req->args());
                if (ret == false) {
                    return basicResponse(false, req->rid(), req->cid());
                }
                _cmp->initQueueConsumer(req->queue_name());//初始化队列的消费者管理句柄
                return basicResponse(true, req->rid(), req->cid());
            }
            void deleteQueue(const deleteQueueRequestPtr &req) {
                _cmp->destroyQueueConsumer(req->queue_name());
                _host->deleteQueue(req->queue_name());
                return basicResponse(true, req->rid(), req->cid());
            }
            //队列的绑定与解除绑定
            void queueBind(const queueBindRequestPtr &req) {
                bool ret = _host->bind(req->exchange_name(), 
                    req->queue_name(), req->binding_key());
                return basicResponse(ret, req->rid(), req->cid());
            }
            void queueUnBind(const queueUnBindRequestPtr &req) {
                _host->unBind(req->exchange_name(), req->queue_name());
                return basicResponse(true, req->rid(), req->cid());
            }
            //消息的发布
            void basicPublish(const basicPublishRequestPtr &req) {
                //1. 判断交换机是否存在
                auto ep = _host->selectExchange(req->exchange_name());
                if (ep.get() == nullptr) {
                    return basicResponse(false, req->rid(), req->cid());
                }
                //2. 进行交换路由,判断消息可以发布到交换机绑定的哪个队列中
                MsgQueueBindingMap mqbm = _host->exchangeBindings(req->exchange_name());
                BasicProperties *properties = nullptr;
                std::string routing_key;
                if (req->has_properties()) {
                    properties = req->mutable_properties();
                    routing_key = properties->routing_key();
                }
                for (auto &binding : mqbm) {
                    if (Router::route(ep->type, routing_key, binding.second->binding_key)) {
                        //3. 将消息添加到队列中(添加消息的管理)
                        _host->basicPublish(binding.first, properties, req->body());
                        //4. 向线程池中添加一个消息消费任务(向指定队列的订阅者去推送消息--线程池完成)
                        auto task = std::bind(&Channel::consume, this, binding.first);
                        _pool->push(task);
                    }
                }
                return basicResponse(true, req->rid(), req->cid());
            }
            //消息的确认
            void basicAck(const basicAckRequestPtr &req) {
                _host->basicAck(req->queue_name(), req->message_id());
                return basicResponse(true, req->rid(), req->cid());
            }
            //订阅队列消息
            void basicConsume(const basicConsumeRequestPtr &req) {
                //1. 判断队列是否存在
                bool ret = _host->existsQueue(req->queue_name());
                if (ret == false) {
                    return basicResponse(false, req->rid(), req->cid());
                }
                //2. 创建队列的消费者
                auto cb = std::bind(&Channel::callback, this, std::placeholders::_1,
                    std::placeholders::_2, std::placeholders::_3);
                //创建了消费者之后,当前的channel角色就是个消费者
                _consumer = _cmp->create(req->consumer_tag(), req->queue_name(), req->auto_ack(), cb);
                return basicResponse(true, req->rid(), req->cid());
            }
            //取消订阅
            void basicCancel(const basicCancelRequestPtr &req) {
                _cmp->remove(req->consumer_tag(), req->queue_name());
                return basicResponse(true, req->rid(), req->cid());
            }
        private:
            void callback(const std::string tag, const BasicProperties *bp, const std::string &body) {
                //针对参数组织出推送消息请求,将消息推送给channel对应的客户端
                basicConsumeResponse resp;
                resp.set_cid(_cid);
                resp.set_body(body);
                resp.set_consumer_tag(tag);
                if (bp) {
                    resp.mutable_properties()->set_id(bp->id());
                    resp.mutable_properties()->set_delivery_mode(bp->delivery_mode());
                    resp.mutable_properties()->set_routing_key(bp->routing_key());
                }
                _codec->send(_conn, resp);
            }
            void consume(const std::string &qname) {
                //指定队列消费消息
                //1. 从队列中取出一条消息
                MessagePtr mp = _host->basicConsume(qname);
                if (mp.get() == nullptr) {
                    DLOG("执行消费任务失败,%s 队列没有消息!", qname.c_str());
                    return;
                }
                //2. 从队列订阅者中取出一个订阅者
                Consumer::ptr cp = _cmp->choose(qname);
                if (cp.get() == nullptr) {
                    DLOG("执行消费任务失败,%s 队列没有消费者!", qname.c_str());
                    return;
                }
                //3. 调用订阅者对应的消息处理函数,实现消息的推送
                cp->callback(cp->tag, mp->mutable_payload()->mutable_properties(), mp->payload().body());
                //4. 判断如果订阅者是自动确认---不需要等待确认,直接删除消息,否则需要外部收到消息确认后再删除
                if (cp->auto_ack) _host->basicAck(qname, mp->payload().properties().id());
            }
            void basicResponse(bool ok, const std::string &rid, const std::string &cid) {
                basicCommonResponse resp;
                resp.set_rid(rid);
                resp.set_cid(cid);
                resp.set_ok(ok);
                _codec->send(_conn, resp);
            }
        private:
            std::string _cid;
            Consumer::ptr _consumer;
            muduo::net::TcpConnectionPtr _conn;
            ProtobufCodecPtr _codec;
            ConsumerManager::ptr _cmp;
            VirtualHost::ptr _host;
            threadpool::ptr _pool;
    };
  1. 信道管理
  • a. 信道的增删查。
cpp 复制代码
    class ChannelManager {
        public:
            using ptr = std::shared_ptr<ChannelManager>;
            ChannelManager(){}
            bool openChannel(const std::string &id, 
                const VirtualHost::ptr &host, 
                const ConsumerManager::ptr &cmp, 
                const ProtobufCodecPtr &codec, 
                const muduo::net::TcpConnectionPtr &conn,
                const threadpool::ptr &pool) {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _channels.find(id);
                if (it != _channels.end()) {
                    DLOG("信道:%s 已经存在!", id.c_str());
                    return false;
                }
                auto channel = std::make_shared<Channel>(id, host, cmp, codec, conn, pool);
                _channels.insert(std::make_pair(id, channel));
                return true;
            }
            void closeChannel(const std::string &id){
                std::unique_lock<std::mutex> lock(_mutex);
                _channels.erase(id);
            }
            Channel::ptr getChannel(const std::string &id) {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _channels.find(id);
                if (it == _channels.end()) {
                    return Channel::ptr();
                }
                return it->second;
            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string, Channel::ptr> _channels;
    };

连接管理模块

向⽤⼾提供⼀个⽤于实现⽹络通信的Connection对象,从其内部可创建出粒度更轻的Channel对象,⽤于与客⼾端进⾏⽹络通信。

  1. 成员信息:
  • a. 连接关联的信道管理句柄(实现信道的增删查)
  • b. 连接关联的实际⽤于通信的muduo::net::Connection连接
  • c. protobuf协议处理的句柄(ProtobufCodec对象)
  • d. 消费者管理句柄
  • e. 虚拟机句柄
  • f. 异步⼯作线程池句柄
  1. 连接操作:
  • a. 提供创建Channel信道的操作
  • b. 提供删除Channel信道的操作
cpp 复制代码
    class Connection {
        public:
            using ptr = std::shared_ptr<Connection>;
            Connection(const VirtualHost::ptr &host, 
                const ConsumerManager::ptr &cmp, 
                const ProtobufCodecPtr &codec, 
                const muduo::net::TcpConnectionPtr &conn,
                const threadpool::ptr &pool) :
                _conn(conn),
                _codec(codec),
                _cmp(cmp),
                _host(host),
                _pool(pool),
                _channels(std::make_shared<ChannelManager>()){}
            void openChannel(const openChannelRequestPtr &req) {
                //1. 判断信道ID是否重复,创建信道
                bool ret = _channels->openChannel(req->cid(), _host, _cmp, _codec, _conn, _pool);
                if (ret == false) {
                    DLOG("创建信道的时候,信道ID重复了");
                    return basicResponse(false, req->rid(), req->cid());
                }
                DLOG("%s 信道创建成功!", req->cid().c_str());
                //3. 给客户端进行回复
                return basicResponse(true, req->rid(), req->cid());
            }
            void closeChannel(const closeChannelRequestPtr &req) {
                _channels->closeChannel(req->cid());
                return basicResponse(true, req->rid(), req->cid());
            }
            Channel::ptr getChannel(const std::string &cid) {
                return _channels->getChannel(cid);
            }
        private:
            void basicResponse(bool ok, const std::string &rid, const std::string &cid) {
                basicCommonResponse resp;
                resp.set_rid(rid);
                resp.set_cid(cid);
                resp.set_ok(ok);
                _codec->send(_conn, resp);
            }
        private:
            muduo::net::TcpConnectionPtr _conn;
            ProtobufCodecPtr _codec;
            ConsumerManager::ptr _cmp;
            VirtualHost::ptr _host;
            threadpool::ptr _pool;
            ChannelManager::ptr _channels;
    };
  1. 连接管理:
  • a. 连接的增删查
cpp 复制代码
    class ConnectionManager {
        public:
            using ptr = std::shared_ptr<ConnectionManager>;
            ConnectionManager() {}
            void newConnection(const VirtualHost::ptr &host, 
                const ConsumerManager::ptr &cmp, 
                const ProtobufCodecPtr &codec, 
                const muduo::net::TcpConnectionPtr &conn,
                const threadpool::ptr &pool) {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it != _conns.end()) {
                    return ;
                }
                Connection::ptr self_conn = std::make_shared<Connection>(host, cmp, codec, conn, pool);
                _conns.insert(std::make_pair(conn, self_conn));
            }
            void delConnection(const muduo::net::TcpConnectionPtr &conn) {
                std::unique_lock<std::mutex> lock(_mutex);
                _conns.erase(conn);
            }
            Connection::ptr getConnection(const muduo::net::TcpConnectionPtr &conn) {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end()) {
                    return Connection::ptr();
                }
                return it->second;
            }
        private:
            std::mutex _mutex;
            std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _conns;
    };

注意:

在RabbitMQ中,虚拟主机是可以随意创建/删除的,但是咱们此处为了实现简单,并没有实现虚拟主机的管理,因此我们默认就只有⼀个虚拟主机的存在,但是在数据结构的设计上我们预留了对于多虚拟主机的管理,从⽽保证不同虚拟主机中的Exchange、Queue、Binding、Message等资源都是相互隔离的。

服务器模块实现

服务器模块我们借助Muduo⽹络库来实现。


BrokerServer模块是对整体服务器所有模块的整合,接收客⼾端的请求,并提供服务。

基于前边实现的简单的翻译服务器代码,进⾏改造,只需要实现服务器内部提供服务的各个业务接即可。

在各个业务处理函数中,也⽐较简单,创建信道后,每次请求过来后,找到请求对应的信道句柄,通过句柄调⽤前边封装好的处理接⼝进⾏请求处理,最终返回处理结果。

cpp 复制代码
    #define DBFILE "/meta.db"
    #define HOSTNAME "MyVirtualHost"
    class Server {
        public:
            typedef std::shared_ptr<google::protobuf::Message> MessagePtr;
            Server(int port, const std::string &basedir): _server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port), 
                "Server", muduo::net::TcpServer::kReusePort),
                _dispatcher(std::bind(&Server::onUnknownMessage, this, std::placeholders::_1, 
                    std::placeholders::_2, std::placeholders::_3)),
                _codec(std::make_shared<ProtobufCodec>(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))),
                _virtual_host(std::make_shared<VirtualHost>(HOSTNAME, basedir, basedir + DBFILE)),
                _consumer_manager(std::make_shared<ConsumerManager>()),
                _connection_manager(std::make_shared<ConnectionManager>()),
                _threadpool(std::make_shared<threadpool>()){
                //针对历史消息中的所有队列,别忘了,初始化队列的消费者管理结构
                QueueMap qm = _virtual_host->allQueues();
                for (auto &q : qm) {
                    _consumer_manager->initQueueConsumer(q.first);
                }
                //注册业务请求处理函数
                _dispatcher.registerMessageCallback<nzq::openChannelRequest>(std::bind(&Server::onOpenChannel, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::closeChannelRequest>(std::bind(&Server::onCloseChannel, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::declareExchangeRequest>(std::bind(&Server::onDeclareExchange, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::deleteExchangeRequest>(std::bind(&Server::onDeleteExchange, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::declareQueueRequest>(std::bind(&Server::onDeclareQueue, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::deleteQueueRequest>(std::bind(&Server::onDeleteQueue, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::queueBindRequest>(std::bind(&Server::onQueueBind, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::queueUnBindRequest>(std::bind(&Server::onQueueUnBind, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::basicPublishRequest>(std::bind(&Server::onBasicPublish, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::basicAckRequest>(std::bind(&Server::onBasicAck, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::basicConsumeRequest>(std::bind(&Server::onBasicConsume, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _dispatcher.registerMessageCallback<nzq::basicCancelRequest>(std::bind(&Server::onBasicCancel, this, 
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

                _server.setMessageCallback(std::bind(&ProtobufCodec::onMessage, _codec.get(),
                    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                _server.setConnectionCallback(std::bind(&Server::onConnection, this, std::placeholders::_1));
            }
            void start() {
                _server.start();
                _baseloop.loop();
            }
        private:
            //打开信道
            void onOpenChannel(const muduo::net::TcpConnectionPtr& conn, const openChannelRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("打开信道时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                return mconn->openChannel(message);
            }
            //关闭信道
            void onCloseChannel(const muduo::net::TcpConnectionPtr& conn, const closeChannelRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("关闭信道时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                return mconn->closeChannel(message);
            }
            //声明交换机
            void onDeclareExchange(const muduo::net::TcpConnectionPtr& conn, const declareExchangeRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("声明交换机时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("声明交换机时,没有找到信道!");
                    return;
                }
                return cp->declareExchange(message);
            }
            //删除交换机
            void onDeleteExchange(const muduo::net::TcpConnectionPtr& conn, const deleteExchangeRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("删除交换机时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("删除交换机时,没有找到信道!");
                    return;
                }
                return cp->deleteExchange(message);
            }
            //声明队列
            void onDeclareQueue(const muduo::net::TcpConnectionPtr& conn, const declareQueueRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("声明队列时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("声明队列时,没有找到信道!");
                    return;
                }
                return cp->declareQueue(message);
            }
            //删除队列
            void onDeleteQueue(const muduo::net::TcpConnectionPtr& conn, const deleteQueueRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("删除队列时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("删除队列时,没有找到信道!");
                    return;
                }
                return cp->deleteQueue(message);
            }
            //队列绑定
            void onQueueBind(const muduo::net::TcpConnectionPtr& conn, const queueBindRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("队列绑定时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("队列绑定时,没有找到信道!");
                    return;
                }
                return cp->queueBind(message);
            }
            //队列解绑
            void onQueueUnBind(const muduo::net::TcpConnectionPtr& conn, const queueUnBindRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("队列解除绑定时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("队列解除绑定时,没有找到信道!");
                    return;
                }
                return cp->queueUnBind(message);
            }
            //消息发布
            void onBasicPublish(const muduo::net::TcpConnectionPtr& conn, const basicPublishRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("发布消息时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("发布消息时,没有找到信道!");
                    return;
                }
                return cp->basicPublish(message);
            }
            //消息确认
            void onBasicAck(const muduo::net::TcpConnectionPtr& conn, const basicAckRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("确认消息时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("确认消息时,没有找到信道!");
                    return;
                }
                return cp->basicAck(message);
            }
            //队列消息订阅
            void onBasicConsume(const muduo::net::TcpConnectionPtr& conn, const basicConsumeRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("队列消息订阅时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("队列消息订阅时,没有找到信道!");
                    return;
                }
                return cp->basicConsume(message);
            }
            //队列消息取消订阅
            void onBasicCancel(const muduo::net::TcpConnectionPtr& conn, const basicCancelRequestPtr& message, muduo::Timestamp) {
                Connection::ptr mconn = _connection_manager->getConnection(conn);
                if (mconn.get() == nullptr) {
                    DLOG("队列消息取消订阅时,没有找到连接对应的Connection对象!");
                    conn->shutdown();
                    return;
                }
                Channel::ptr cp = mconn->getChannel(message->cid());
                if (cp.get() == nullptr) {
                    DLOG("队列消息取消订阅时,没有找到信道!");
                    return;
                }
                return cp->basicCancel(message);
            }
            void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp) {
                LOG_INFO << "onUnknownMessage: " << message->GetTypeName();
                conn->shutdown();
            }
            void onConnection(const muduo::net::TcpConnectionPtr &conn) {
                if (conn->connected()) {
                    _connection_manager->newConnection(_virtual_host, _consumer_manager, _codec, conn, _threadpool);
                }else {
                    _connection_manager->delConnection(conn);
                }
            }
        private:
            muduo::net::EventLoop _baseloop;
            muduo::net::TcpServer _server;//服务器对象
            ProtobufDispatcher _dispatcher;//请求分发器对象--要向其中注册请求处理函数
            ProtobufCodecPtr _codec;//protobuf协议处理器--针对收到的请求数据进行protobuf协议处理
            VirtualHost::ptr _virtual_host;
            ConsumerManager::ptr _consumer_manager;
            ConnectionManager::ptr _connection_manager;
            threadpool::ptr _threadpool;
    };

server.cc

cpp 复制代码
#include "broker.hpp"

int main()
{
    nzq::Server server(8085, "./data/");
    server.start();
    return 0;
}
相关推荐
阿望要努力上研究生2 小时前
若依项目搭建(黑马经验)
java·redis·node.js·maven·管理系统
一只脑洞君2 小时前
Kubernetes(K8s)的简介
java·容器·kubernetes
zygswo2 小时前
程序猿成长之路之设计模式篇——设计模式简介
java·设计模式
除了代码啥也不会3 小时前
springboot项目发送邮件
java·spring boot·spring
无敌の星仔4 小时前
一个月学会Java 第7天 字符串与键盘输入
java·开发语言·python
GGBondlctrl4 小时前
【JavaEE初阶】多线程案列之定时器的使用和内部原码模拟
java·开发语言·定时器·timer的使用·定时器代码模拟
多多*4 小时前
OJ在线评测系统 微服务高级 Gateway网关接口路由和聚合文档 引入knife4j库集中查看管理并且调试网关项目
java·运维·微服务·云原生·容器·架构·gateway
惜.己5 小时前
java中日期时间类的api
java·开发语言·intellij-idea·idea·intellij idea
橘子海全栈攻城狮6 小时前
【源码+文档+调试讲解】基于Android的固定资产借用管理平台
android·java·spring boot·后端·python·美食