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

news/2024/10/5 14:04:00 标签: java-rabbitmq, rabbitmq, java

文章目录

  • ⽹络通信协议设计
  • 信道管理模块
  • 连接管理模块
  • 服务器模块实现

⽹络通信协议设计

在这里插入图片描述
其中⽣产者和消费者都是客⼾端,它们都需要通过⽹络和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

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. 提供发布&确认消息操作
    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. 信道的增删查。
    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信道的操作
    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. 连接的增删查
    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模块是对整体服务器所有模块的整合,接收客⼾端的请求,并提供服务。

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

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

    #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

#include "broker.hpp"

int main()
{
    nzq::Server server(8085, "./data/");
    server.start();
    return 0;
}

http://www.niftyadmin.cn/n/5690987.html

相关文章

Linux 进程状态、僵尸进程与孤儿进程

目录 0.前言 1. 进程状态 1.1 定义 1.2 常见进程 2.僵尸进程 2.1 定义 2.2 示例 2.3 僵尸进程的危害与防止方法 3. 孤儿进程 3.1 介绍 3.2 示例 4.小结 &#xff08;图像由AI生成&#xff09; 0.前言 在上一篇文章中&#xff0c;我们介绍了进程的基本概念、进程控制块&#…

小米 MIX FOLD工程固件 更换字库修复分区 资源预览与刷写说明

小米 MIX FOLD机型代号 :cetus 该手机搭载骁龙888旗舰处理器 。对于一些因为字库问题损坏导致的故障,更换字库后要先刷写对应的工程底层修复固件。绑定cpu后在写入miui量产固件。 通过博文了解 1💝💝💝-----此机型工程固件的资源刷写注意事项 2💝💝💝-----此…

通过 Caddy2 部署 WebDAV 服务器

今天我们在阿贝云的免费服务器上进行一次有趣的部署测试。阿贝云提供的这款免费云服务器&#xff0c;虽然配置为1核CPU、1G内存、10G硬盘、5M带宽&#xff0c;但其稳定性和易用性让人惊喜&#xff0c;真是不错的免费服务器&#xff01;无论是小项目还是实验环境&#xff0c;阿贝…

前端Vue项目的自动打包、上传与部署

文章目录 前言思路与流程脚本实现1. 打包前端项目2. 上传前端项目4. 传递密码5. 代码优化完整脚本结语前言 在实际项目开发中,并不是所有项目都会配置 CI/CD 流程,特别是在中小型团队或者公司内部测试环境中,很多时候我们仍然需要手动打包、上传和部署项目。这个过程虽然简…

(Django)初步使用

前言 Django 是一个功能强大、架构良好、安全可靠的 Python Web 框架&#xff0c;适用于各种规模的项目开发。它的高效开发、数据库支持、安全性、良好的架构设计以及活跃的社区和丰富的文档&#xff0c;使得它成为众多开发者的首选框架。 目录 安装 应用场景 良好的架构设计…

职场祛魅:判断2B企业和外包公司?

长假期间有初入职场的小伙伴跟猫哥聊天&#xff0c;说起来外包公司&#xff0c;并认为&#xff1a;外包公司也为企业提供服务&#xff0c;2B从名字上判断就是为企业服务的。 一、怎么判断一个企业是2B而不是外包&#xff1f; 以下是猫哥从业N年的一点粗浅认识&#xff1a; 要…

C语言复习概要(二)

本文目录 C语言中的数组与函数详解1. 引言2. 数组2.1. 什么是数组&#xff1f;语法&#xff1a;示例&#xff1a; 2.2. 数组的初始化示例 1&#xff1a;在声明时初始化示例 2&#xff1a;部分初始化示例 3&#xff1a;运行时赋值 2.3. 数组的访问与修改示例&#xff1a; 2.4. 多…

web网页项目--用户登录,注册页面代码

index.html <!DOCTYPE html> <html lang"zxx"><head><title>xxx注册</title><!-- Meta tags --><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&q…