仿RabbitMQ实现消息队列-客户端模块实现

订阅者模块设计与实现

一、模块概述

订阅者模块是消息队列消费层的基础实体单元,用于封装消费者身份、订阅关系、消费模式与回调接口。作为消费者管理器与信道模块的底层支撑,该模块采用轻量化结构体设计,仅负责属性存储与生命周期管理,职责单一、对接简洁。

二、核心功能

  1. 定义消费者唯一标识、订阅队列、自动确认模式
  2. 封装消息到达后的异步回调接口
  3. 提供构造/析构日志,便于追踪对象生命周期;
  4. 统一使用智能指针托管,实现资源自动释放。

三、核心结构

  • tag:消费者唯一标签
  • qname:订阅的目标队列
  • auto_ack:是否自动消息确认
  • callback:消息推送回调函数

四、模块代码

cpp 复制代码
#ifndef __M_CONSUMER_H__
#define __M_CONSUMER_H__

#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_msg.pb.h"

namespace Fy_mq{
    using ConsumerCallback = std::function<void(const std::string &, const BasicProperties *bp, const std::string &)>;
    
    struct Consumer {
        using ptr = std::shared_ptr<Consumer>;

        std::string tag;
        std::string qname;
        bool auto_ack;
        ConsumerCallback callback;
        
        Consumer(){ DLOG("new Consumer: %p",this); }

        Consumer(const std::string &ctag,const std::string &queue_name,bool ack_flag,const ConsumerCallback &cb):
            tag(ctag),qname(queue_name),auto_ack(ack_flag),callback(std::move(cb)){
            DLOG("new Consumer: %p",this);
        }

        ~Consumer(){ DLOG("del Consumer: %p", this); }
    };
};

#endif

信道管理模块设计与实现

一、模块概述

客户端信道管理模块是自研消息队列客户端核心通信组件,负责客户端与服务端的会话建立、业务请求交互、消息接收回调及信道生命周期管控。模块基于Muduo网络库与Protobuf协议,采用Channel+ChannelManager双层架构,封装了消息队列全业务请求接口,实现请求响应同步等待、线程安全调度,为客户端提供简洁、可靠的通信支撑,是客户端与服务端交互的核心桥梁。

二、核心功能

  1. 信道生命周期管理:自动生成唯一信道ID,支持信道创建、打开、关闭,析构时自动取消订阅,避免资源泄漏;
  2. 全业务请求封装:提供交换机/队列声明、删除、绑定、解绑,消息发布、确认,消费者订阅、取消订阅等全接口;
  3. 同步响应机制:通过条件变量与互斥锁,实现请求发送后同步等待服务端响应,保证交互可靠性;
  4. 消息消费回调:接收服务端推送消息,通过绑定的消费者回调函数,将消息分发至业务层处理;
  5. 全局信道管控:通过ChannelManager实现多信道的统一创建、删除、查询,保证多线程并发安全。

三、核心架构设计

1. 模块结构

采用"单信道会话+全局管理器"双层设计:

  • Channel:单个通信会话载体,封装TCP连接、协议编解码器,维护消费者对象与请求响应缓存,处理具体业务请求;
  • ChannelManager:全局信道管理器,基于互斥锁+哈希表,实现所有信道的线程安全管理,提供创建、删除、查询接口。

2. 核心成员与依赖

  • 核心成员:信道唯一ID(_cid)、TCP连接指针、Protobuf编解码器指针、消费者对象、互斥锁、条件变量、响应缓存哈希表;
  • 依赖模块:Muduo网络库(TCP连接、编解码)、Protobuf协议(请求/响应封装)、消费者模块(Consumer)、公共工具(日志、UUID生成)。

四、核心接口实现

1. 信道基础操作

  • 信道创建:自动生成唯一CID,绑定TCP连接与编解码器;
  • 打开/关闭信道:向服务端发送对应请求,同步等待响应,完成会话建立与释放;
  • 信道标识获取:提供cid()接口,返回当前信道唯一ID,用于全局定位。

2. 业务请求接口

封装消息队列全业务请求,统一设置请求ID(rid)与信道ID(cid),确保请求与响应一一对应:

  • 交换机管理:declareExchange(声明)、deleteExchange(删除);
  • 队列管理:declareQueue(声明)、deleteQueue(删除)、QueueBind(绑定)、QueueUnBind(解绑);
  • 消息操作:basicPublish(发布消息)、basicAck(消息确认);
  • 消费者操作:basicConsumer(订阅消息)、basicCancel(取消订阅)。

3. 响应与消息处理

  • 响应缓存:通过putBasicResponse接口接收服务端响应,存入哈希表并唤醒等待线程;
  • 同步等待:waitResponse接口通过条件变量阻塞,等待对应请求的响应,接收后自动清理缓存;
  • 消息推送:consume接口接收服务端推送消息,校验消费者标识后,通过回调函数分发至业务层。

4. 全局信道管理

ChannelManager提供简洁的信道管控接口,所有操作加互斥锁,保证多线程安全:

  • create:创建信道并加入全局管理;
  • remove:根据CID删除信道,释放资源;
  • get:根据CID查询信道,用于请求分发与消息处理。

五、模块代码

cpp 复制代码
#ifndef __M_CHANNEL_H__
#define __M_CHANNEL_H__

#include "muduo/net/TcpConnection.h"
#include "muduo/proto/codec.h"
#include "muduo/proto/dispatcher.h"

#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include "../mqcommon/mq_proto.pb.h"

#include "mq_consumer.hpp"

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <unordered_map>

namespace Fy_mq{
    using ProtobufCodecPtr = std::shared_ptr<ProtobufCodec>;
    using basicConsumeResponsePtr = std::shared_ptr<basicConsumeResponse>;
    using basicCommonResponsePtr = std::shared_ptr<basicCommonResponse>;

    class Channel{
    public:
        using ptr = std::shared_ptr<Channel>;

        Channel(const muduo::net::TcpConnectionPtr& conn,const ProtobufCodecPtr &codec):
            _cid(UUIDHelper::uuid()),_conn(conn),_codec(codec){}
        
        ~Channel(){
            basicCancel();
        }

        std::string cid(){
            return _cid;
        }

        bool openChannel(){
            std::string rid = UUIDHelper::uuid();
            openChannelRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            _codec->send(_conn,req);
            basicCommonResponsePtr resp = waitResponse(rid);
            return resp->ok();
        }

        void closeChannel(){
            std::string rid = UUIDHelper::uuid();
            closeChannelRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            _codec->send(_conn,req);
            waitResponse(rid);
        }

        bool declareExchange(
            const std::string &name,
            ExchangeType type,
            bool durable,
            bool auto_delete,
            google::protobuf::Map<std::string,std::string> &args){
            std::string rid = UUIDHelper::uuid();
            declareExchangeRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_exchange_name(name);
            req.set_exchange_type(type);
            req.set_durable(durable);
            req.set_auto_delete(auto_delete);
            req.mutable_args()->swap(args);
            _codec->send(_conn, req);
            basicCommonResponsePtr resp = waitResponse(rid);
            return resp->ok();
        }

        void deleteExchange(const std::string &name){
            std::string rid = UUIDHelper::uuid();
            deleteExchangeRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_exchange_name(name);
            _codec->send(_conn,req);
            waitResponse(rid);
        }

        bool declareQueue(
            const std::string &qname,
            bool qdurable,
            bool qexclusive,
            bool qauto_delete,
            google::protobuf::Map<std::string,std::string> &qargs){
            std::string rid = UUIDHelper::uuid();
            declareQueueRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_queue_name(qname);
            req.set_durable(qdurable);
            req.set_exclusive(qexclusive);
            req.set_auto_delete(qauto_delete);
            req.mutable_args()->swap(qargs);
            _codec->send(_conn, req);
            basicCommonResponsePtr resp = waitResponse(rid);
            return resp->ok();
        }

        void deleteQueue(const std::string &qname){
            std::string rid = UUIDHelper::uuid();
            deleteQueueRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_queue_name(qname);
            _codec->send(_conn,req);
            waitResponse(rid);
        }
        
        bool QueueBind(
            const std::string &ename,
            const std::string &qname,
            const std::string &key){
            std::string rid = UUIDHelper::uuid();
            queueBindRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_exchange_name(ename);
            req.set_queue_name(qname);
            req.set_binding_key(key);
            _codec->send(_conn, req);
            basicCommonResponsePtr resp = waitResponse(rid);
            return resp->ok();
        }

        void QueueUnBind(const std::string &ename,const std::string &qname){
            std::string rid = UUIDHelper::uuid();
            queueUnBindRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_exchange_name(ename);
            req.set_queue_name(qname);
            _codec->send(_conn,req);
            waitResponse(rid);
        }

        void basicPublish(const std::string &ename,const BasicProperties *bp,const std::string &body){
            std::string rid = UUIDHelper::uuid();
            basicPublishRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_exchange_name(ename);
            req.set_body(body);
            if(bp != nullptr){
                req.mutable_properties()->set_id(bp->id());
                req.mutable_properties()->set_deliver_mode(bp->deliver_mode());
                req.mutable_properties()->set_routing_key(bp->routing_key());
            }
            _codec->send(_conn,req);
            waitResponse(rid);
        }

        void basicAck(const std::string &msgid){
            if(_consumer.get() == nullptr){
                DLOG("消息确认时,找不到消费者信息!");
                return;
            }
            std::string rid = UUIDHelper::uuid();
            basicAckRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_queue_name(_consumer->qname);
            req.set_message_id(msgid);
            _codec->send(_conn,req);
            waitResponse(rid);
        }

        void basicCancel(){
            if(_consumer.get() == nullptr){
                return;
            }
            std::string rid = UUIDHelper::uuid();
            basicCancelRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_queue_name(_consumer->qname);
            req.set_consumer_tag(_consumer->tag);
            _codec->send(_conn,req);
            waitResponse(rid);
            _consumer.reset();
        }

        bool basicConsumer(
            const std::string &consumer_tag,
            const std::string &queue_name,
            bool auto_ack,
            const ConsumerCallback &cb){
            if(_consumer.get() != nullptr){
                DLOG("当前信道已订阅其他队列消息!");
                return false;
            }
            std::string rid = UUIDHelper::uuid();
            basicConsumeRequest req;
            req.set_rid(rid);
            req.set_cid(_cid);
            req.set_queue_name(queue_name);
            req.set_consumer_tag(consumer_tag);
            req.set_auto_ack(auto_ack);
            _codec->send(_conn,req);
            basicCommonResponsePtr resp = waitResponse(rid);
            if(resp->ok() == false){
                DLOG("添加订阅失败!");
                return false;
            }
            _consumer = std::make_shared<Consumer>(consumer_tag,queue_name,cb);
            return true;
        }

    public:
        void putBasicResponse(const basicCommonResponsePtr &resp){
            std::unique_lock<std::mutex> lock(_mutex);
            _basic_resp.insert(std::make_pair(resp->rid(),resp));
            _cv.notify_all();
        }

        void consume(const basicConsumeResponsePtr &resp) {
            if(_consumer.get() == nullptr){
                DLOG("处理消息时,未找到订阅者消息!");
                return;
            }
            if (_consumer->tag != resp->consumer_id()) {
                DLOG("收到的推送消息中的消费者标识,与当前信道消费者标识不一致!");
                return ;
            }
            _consumer->callback(resp->consumer_id(),resp->mutable_properties(),resp->body());
        }

    private:
        basicCommonResponsePtr waitResponse(const std::string &rid){
            std::unique_lock<std::mutex> lock(_mutex);
            _cv.wait(lock,[&rid,this](){
                return _basic_resp.find(rid) != _basic_resp.end();
            });
            basicCommonResponsePtr basic_resp = _basic_resp[rid];
            _basic_resp.erase(rid);
            return basic_resp;
        }

    private:
        std::string _cid;
        muduo::net::TcpConnectionPtr _conn;
        ProtobufCodecPtr _codec;
        Consumer::ptr _consumer;
        std::mutex _mutex;
        std::condition_variable _cv;
        std::unordered_map<std::string,basicCommonResponsePtr> _basic_resp;
    };

    class ChannelManager{
    public:
        using ptr = std::shared_ptr<ChannelManager>;

        ChannelManager(){}

        Channel::ptr create(const muduo::net::TcpConnectionPtr &conn,
            const ProtobufCodecPtr &codec) {
            std::unique_lock<std::mutex> lock(_mutex);
            auto channel = std::make_shared<Channel>(conn, codec);
            _channels.insert(std::make_pair(channel->cid(),channel));
            return channel;
        }

        void remove(const std::string &cid){
            std::unique_lock<std::mutex> lock(_mutex);
            _channels.erase(cid);
        }

        Channel::ptr get(const std::string &cid){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(cid);
            if(it == _channels.end()){
                return Channel::ptr();
            }
            return it->second;
        }
    private:
        std::mutex _mutex;
        std::unordered_map<std::string,Channel::ptr> _channels;
    };
}

#endif

六、模块特点

  1. 线程安全:所有共享资源操作均加互斥锁,条件变量实现同步等待,适配多线程并发场景;
  2. 可靠性高:请求与响应通过rid绑定,避免错乱,析构自动清理资源,无内存泄漏;
  3. 接口简洁:封装全业务接口,客户端可直接调用,无需关注底层通信细节;
  4. 可扩展性强:模块化设计,与其他客户端模块低耦合,便于后续功能迭代;
  5. 可调试性好:关键操作打印日志,便于定位请求异常、消息推送失败等问题。

异步工作线程模块设计与实现

一、模块概述

AsyncWorker 是自研消息队列客户端的异步支撑核心模块 ,用于分离网络IO线程用户业务线程,避免网络操作阻塞业务逻辑,同时为消息消费、异步回调提供独立的线程环境。

模块封装 Muduo EventLoop 线程 + 自定义线程池,实现网络事件循环与业务任务异步化,是客户端高并发、非阻塞设计的关键组件。

二、核心功能

  1. 网络IO线程 :通过 EventLoopThread 创建独立线程运行 Muduo 事件循环,处理网络收发、协议解析,不阻塞主线程;
  2. 业务异步线程池:内置线程池用于处理消息消费、用户回调等耗时业务,避免阻塞IO线程;
  3. 轻量封装:仅做线程与事件循环的统一托管,结构简洁、无冗余逻辑。

三、核心设计

  • EventLoopThread:提供独立的 Reactor 事件循环线程,负责客户端网络 IO;
  • threadpool:业务线程池,负责异步执行消息回调、耗时处理;
  • 统一封装为 AsyncWorker,方便上层连接、信道模块直接使用。

四、模块代码

cpp 复制代码
#ifndef __M_WORKER_H__
#define __M_WORKER_H__

#include "muduo/net/EventLoopThread.h"
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_threadpool.hpp"

namespace Fy_mq {
    class AsyncWorker {
    public:
        using ptr = std::shared_ptr<AsyncWorker>;
        
        // Muduo 网络事件循环线程
        muduo::net::EventLoopThread loopthread;
        // 自定义业务线程池
        threadpool pool;
    };
}

#endif

连接管理模块设计与实现

一、模块概述

客户端连接管理模块是自研消息队列客户端网络通信核心,基于Muduo网络库与Protobuf协议构建,负责客户端与服务端的TCP连接建立、连接状态维护、协议消息分发及信道统一管控。作为客户端各模块的底层支撑,该模块实现了网络IO与业务逻辑的解耦,通过同步等待机制确保连接可靠性,通过异步线程池提升消息处理效率,是客户端与服务端实现稳定通信的关键桥梁。

模块遵循高内聚、低耦合设计原则,封装了连接建立、信道管理、消息转发等核心逻辑,对外提供简洁的接口,无需上层模块关注底层网络细节,可直接与信道模块、异步工作线程模块无缝对接,支撑整个客户端的业务运转。

二、核心功能

  1. 连接生命周期管理:发起TCP连接请求,通过CountDownLatch同步等待连接就绪,避免未连接完成时进行业务操作;连接断开时自动释放资源,重置连接指针,保证资源安全回收。
  2. 协议处理与消息分发:集成Protobuf编解码器(ProtobufCodec)与消息分发器(ProtobufDispatcher),自动完成消息的序列化与反序列化,根据消息类型(通用响应、消费推送)分发至对应处理函数,支持未知消息的异常处理。
  3. 信道统一管控:通过信道管理器(ChannelManager),实现当前连接下所有信道的创建、查询、删除,提供openChannel、closeChannel接口,简化上层对信道的操作。
  4. 异步消息消费:收到服务端推送的消费消息后,提交至异步工作线程池(AsyncWorker)执行回调函数,分离网络IO线程与业务消费线程,避免阻塞网络通信。
  5. 异常处理:对未知协议类型的消息进行日志记录并主动关闭连接,对信道查询失败等异常场景打印日志,便于问题定位与调试。

三、核心架构设计

1. 模块依赖

  • 网络依赖:Muduo网络库(TcpClient、EventLoopThread、TcpConnection),负责TCP连接建立、网络事件驱动与IO处理;
  • 协议依赖:Protobuf编解码器与分发器,实现消息的编解码与类型分发;
  • 内部依赖:异步工作线程模块(AsyncWorker)提供IO线程与业务线程池,信道模块(Channel)与信道管理器(ChannelManager)实现信道管控;
  • 工具依赖:CountDownLatch实现连接同步等待,日志工具(ILOG/DLOG)实现异常与调试信息输出。

2. 核心成员与作用

核心成员 类型 作用
_conn TcpConnectionPtr 维护客户端与服务端的TCP连接指针
_latch CountDownLatch 同步等待连接建立完成,避免连接未就绪时执行业务操作
_client TcpClient Muduo客户端,负责发起连接、网络消息收发
_dispatcher ProtobufDispatcher 消息分发器,根据消息类型回调对应处理函数
_codec ProtobufCodecPtr 协议编解码器,实现消息的序列化与反序列化
_worker AsyncWorker::ptr 异步工作器,提供独立IO线程与业务线程池
_channel_manager ChannelManager::ptr 信道管理器,统一管理当前连接下的所有信道

3. 核心流程

  1. 连接初始化:构造Connection对象时,传入服务端IP、端口与异步工作器,启动Muduo事件循环线程,发起TCP连接请求,通过CountDownLatch同步等待连接建立完成。
  2. 回调注册:注册通用响应(basicCommonResponse)、消费推送响应(basicConsumeResponse)的处理回调,以及未知消息的异常处理回调;绑定消息接收回调与连接状态变更回调。
  3. 信道操作:上层通过openChannel接口创建信道,由信道管理器统一管理,创建成功后完成信道握手;通过closeChannel接口关闭信道并从管理器中移除。
  4. 消息处理:收到服务端响应消息时,分发器根据消息类型,将通用响应转发至对应信道,将消费推送消息提交至线程池异步执行回调。
  5. 连接关闭:当TCP连接断开时,重置连接指针,释放相关资源,确保无内存泄漏。

四、核心接口实现

1. 构造函数

初始化Muduo客户端、消息分发器、协议编解码器,注册各类回调函数,发起TCP连接并同步等待连接就绪,确保连接建立后再进行后续业务操作。核心逻辑包括绑定消息接收、连接状态变更回调,注册响应消息处理函数,完成客户端初始化。

2. 信道操作接口

  • openChannel:通过信道管理器创建信道,调用信道的openChannel方法完成握手,若握手失败则返回空指针,打印调试日志。
  • closeChannel:调用信道的closeChannel方法关闭信道,再通过信道管理器移除该信道,释放信道资源。

3. 响应处理接口

  • basicResponse:接收服务端通用响应消息,根据消息中的信道ID(cid)查询对应的信道,将响应消息转发至该信道,唤醒信道中等待响应的线程。
  • consumeResponse:接收服务端消费推送消息,查询对应的信道,将消息处理逻辑提交至异步线程池,避免阻塞网络IO线程。
  • onUnknownMessage:处理未知类型的消息,打印日志并主动关闭连接,提升系统健壮性。

4. 连接状态回调

  • onConnection:监听TCP连接状态,连接建立时唤醒等待线程、保存连接指针;连接断开时重置连接指针,释放连接资源。

五、模块代码

cpp 复制代码
#ifndef __M_CONNECTION_H__
#define __M_CONNECTION_H__

#include "muduo/proto/dispatcher.h"
#include "muduo/proto/codec.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpClient.h"
#include "muduo/net/EventLoopThread.h"
#include "muduo/base/CountDownLatch.h"

#include "mq_channel.hpp"
#include "mq_worker.hpp"

namespace Fy_mq{
    class Connection{
    public:
        using ptr = std::shared_ptr<Connection>;
        using MessagePtr = std::shared_ptr<google::protobuf::Message>;

        Connection(const std::string &sip,int sport,const AsyncWorker::ptr &worker):
            _latch(1),_client(worker->loopthread.startLoop(),muduo::net::InetAddress(sip,sport),"Client"),
            _dispatcher(std::bind(&Connection::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))),
            _worker(worker),
            _channel_manager(std::make_shared<ChannelManager>()){

            _dispatcher.registerMessageCallback<basicCommonResponse>(std::bind(&Connection::basicResponse,this,
            std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));

            _dispatcher.registerMessageCallback<basicConsumeResponse>(std::bind(&Connection::consumeResponse,this,
            std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));

            _client.setMessageCallback(std::bind(&ProtobufCodec::onMessage,_codec.get(),
            std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));

            _client.setConnectionCallback(std::bind(&Connection::onConnection,this,std::placeholders::_1));

            _client.connect();
            _latch.wait();
        }

        Channel::ptr openChannel(){
            Channel::ptr channel = _channel_manager->create(_conn,_codec);
            bool ret = channel->openChannel();
            if(ret == false){
                DLOG("打开信道失败!");
                return Channel::ptr();
            }
            return channel;
        }

        void closeChannel(const Channel::ptr &channel){
            channel->closeChannel();
            _channel_manager->remove(channel->cid());
        }
    private:
        void basicResponse(const muduo::net::TcpConnectionPtr &conn,const basicCommonResponsePtr &message,muduo::Timestamp) {
            //1.找到信道
            Channel::ptr channel = _channel_manager->get(message->cid());
            if(channel.get() == nullptr){
                DLOG("未找到信道消息!");
                return;
            }
            //2.将得到的响应对象,添加到信道的基础响应hash_map中
            channel->putBasicResponse(message);//此时会唤醒等待的线程
        }

        void consumeResponse(const muduo::net::TcpConnectionPtr &conn,const basicConsumeResponsePtr &message,muduo::Timestamp){
            Channel::ptr channel = _channel_manager->get(message->cid());
            if(channel.get() == nullptr){
                DLOG("未找到信道消息!");
                return;
            }
            _worker->pool.push([channel,message](){
                channel->consume(message);
            });
        }

        void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp) {
            ILOG("onUnknownMessage: %s",message->GetTypeName().c_str());
            conn->shutdown();
        }

        void onConnection(const muduo::net::TcpConnectionPtr&conn){
            if (conn->connected()) {
                _latch.countDown();//唤醒主线程中的阻塞
                _conn = conn;
            }else {
                //连接关闭时的操作
                _conn.reset();
            }
        }

    private:
        muduo::net::TcpConnectionPtr _conn;//客户端对应的连接
        muduo::CountDownLatch _latch;//实现同步的
        muduo::net::TcpClient _client;//客户端
        ProtobufDispatcher _dispatcher;//请求分发器
        ProtobufCodecPtr _codec;//协议处理器
        AsyncWorker::ptr _worker;
        ChannelManager::ptr _channel_manager;
    };
}

#endif
相关推荐
想唱rap1 小时前
传输层协议之UDP
java·linux·网络·c++·网络协议·mysql·udp
春蕾夏荷_7282977251 小时前
2、c++ acl tcp服务器客户端简单实例-客户端(2)
服务器·c++·tcp/ip
一只小小的芙厨1 小时前
KMP总结
算法
生成论实验室2 小时前
《事件关系阴阳博弈动力学:识势应势之道》第十一篇:双脑协同——WOLM与大模型的共生智能
人工智能·算法·语言模型·架构·创业创新
上弦月-编程2 小时前
高效编程利器:转移表技术解析
c语言·开发语言·数据结构·算法·排序算法
薇茗2 小时前
【初阶数据结构】 左右逢源的分支诗律 二叉树2
c语言·数据结构·算法·二叉树
AZaLEan__2 小时前
算法考核题解
算法
MediaTea3 小时前
AI 术语通俗词典:ID3 算法
人工智能·算法
Morwit3 小时前
【力扣hot100】 221. 最大正方形
前端·算法·leetcode