Channel信道管理模块

目录

一.Channel模块介绍

二.网络通信请求和响应的定义

三.Channel的定义

成员变量

构造和析构函数

CommonResponse 

交换机的声明与删除

队列的声明和删除

绑定和解绑

消息的发布和确认

consume函数(消费任务)

callback函数(消息处理)

消息确认

消息订阅与取消订阅

四.ChannelManager的实现

成员变量和方法

信道的新增删除获取

五.全部代码

一.Channel模块介绍

对于信道管理Channel来说,这是一个在网络通信中的概念,表示的就是通信通道,当进行网络通信的时候,必然是借助一个网络通信连接来完成的,为了更加方便的进行资源的利用,因此要对于通信连接进行了一个更加进一步的细化,细化出了通信通道。

对于用户来说,一个通信通道就是网络通信的载体,而一个真正的通信连接,是可以创建出多个通信通道每一个信道和信道之间,在使用者的角度来看是相互独立的存在,所有的网络通信服务都是由信道提供的

二.网络通信请求和响应的定义

用protobuf定义出来的请求和响应格式,将所需要的参数封装起来,方便后续使用。

都包含请求id:rid,信道id:chid

syntax = "proto3";

package msg;

import "msg.proto";

//信道相关
message OpenChannelReq
{
    string rid = 1;
    string chid = 2;
};
message CloseChannelReq
{
    string rid = 1;
    string chid = 2;
};

//交换机相关
message DeclareExchangeReq
{
    string rid = 1; // 请求id
    string chid = 2; // 信道id
    string e_name = 3;// 交换机名称
    ExchangeType e_type = 4;// 交换机类型
    bool durable = 5;// 持久化
    bool auto_delete = 6;// 自动删除
    map<string, string> args = 7;// 其他参数
};
message RemoveExchangeReq
{
    string rid = 1;
    string chid = 2;
    string e_name = 3;
};

//队列相关
message DeclareQueueReq
{
    string rid = 1;
    string chid = 2;
    string q_name = 3;
    bool durable = 4;
    bool exclusive = 5;
    bool auto_delete = 6;
    map<string, string> args = 7;
};
message RemoveQueueReq
{
    string rid = 1;
    string chid = 2;
    string q_name = 3;
};

//绑定相关
message BindReq
{
    string rid = 1;
    string chid = 2;
    string e_name = 3;
    string q_name = 4;
    string bind_key = 5;
};
message UnbindReq
{
     string rid = 1;
    string chid = 2;
    string e_name = 3;
    string q_name = 4;
};

//消息相关
message BasicPublishReq//发布消息
{
    string rid = 1;
    string chid = 2;
    string e_name = 3; // 消息发布给交换机
    BasicAttributes attr = 4;// 消息属性
    string body = 5;// 消息体
};
message BasicAckReq//消息确认
{
    string rid = 1;
    string chid = 2;
    string q_name = 3;
    string messagg_id = 4;
};
// 订阅和取消订阅
message BasicConsumeReq //某个消费者订阅某个队列
{
    string rid = 1;
    string chid = 2;
    string consumer_tag = 3;
    string q_name = 4;
    bool auto_ack = 5;
};
message BasicCancelReq
{
    string rid = 1;
    string chid = 2;
    string consumer_tag = 3;
    string q_name = 4;
};

//消息的推送
message BasicConsumeRsp
{
    string chid = 1;// 信道id
    string consumer_tag = 2;
    string body = 3;
    BasicAttributes attr = 4;
}
//通用响应
message BasicCommonResponse
{
    string rid = 1; // 响应id,与请求id一致
    string chid = 2;
    bool success = 3;
};

三.Channel的定义

成员变量

class Channel
{
private:
    std::string _chid;                  // 信道ID
    VirtualHost::ptr _vhost;            // 虚拟主机句柄
    Consumer::ptr _consumer;            // 信道关联的消费者
    ConsumerManager::ptr _cmp;          // 消费者管理器
    ProtobufCodecPtr _codec;            // Protobuf协议处理器, 处理接收到的请求数据
    muduo::net::TcpConnectionPtr _conn; // TCP连接
    ThreadPool::ptr _pool;              // 线程池
};
  • _chid:每个信道都有一个唯一的ID用于标识。
  • _vhost:虚拟主机,管理多个交换机、队列的对象。
  • _consumer:当前信道的消费者。
  • _cmp:管理所有消费者的消费者管理器。
  • _codec:负责处理Protobuf协议的编解码器。
  • _conn:通过这个TCP连接与客户端进行通信。
  • _pool:线程池,用于处理异步任务。

构造和析构函数

Channel类提供了两个构造函数,一个是默认构造函数,另一个是带参数的构造函数。
析构函数则用于在信道销毁时,移除该信道channel对应的消费者。

Channel()
{
    DLOG("channel:%p created", this);
}

Channel(const std::string &chid,
        const VirtualHost::ptr &vhost,
        const ConsumerManager::ptr &cmp,
        const muduo::net::TcpConnectionPtr &conn,
        const ProtobufCodecPtr &codec,
        const ThreadPool::ptr &pool)
    : _chid(chid),
      _vhost(vhost),
      _cmp(cmp),
      _codec(codec),
      _conn(conn),
      _pool(pool)
{
    DLOG("channel:%p created", this);
}

~Channel()
{
    if (_cmp.get() != nullptr)
    {
        _cmp->remove(_consumer->_qname, _consumer->_tag);
        DLOG("channel:%p destroyed", this);
    }
}

CommonResponse 

完成某个常规操作时,发回给客户端的默认相应,方便客户端判断该操作是否成功完成。

  void basicCommonResponse(const std::string &rid, const std::string &chid, bool success)
        {
            msg::BasicCommonResponse resp;
            resp.set_rid(rid);
            resp.set_chid(chid);
            resp.set_success(success);
            return _codec->send(_conn, resp);
        }

交换机的声明与删除

  • declareExchange:调用_vhostdeclareExchange方法声明一个交换机,并返回操作结果。
  • removeExchange:调用_vhostremoveExchange方法删除一个交换机,并返回操作结果。
void declareExchange(const DeclareExchangeReqPtr &req)
{
    bool ret = _vhost->declareExchange(req->e_name(),
                                       req->e_type(), req->durable(),
                                       req->auto_delete(), req->args());
    return basicCommonResponse(req->rid(), req->chid(), ret);
}

void removeExchange(const RemoveExchangeReqPtr &req)
{
    bool ret = _vhost->removeExchange(req->e_name());
    return basicCommonResponse(req->rid(), req->chid(), ret);
}

队列的声明和删除

  • declareQueue:在_vhost中声明一个队列,并且在消费者管理器_cmp中初始化该队列的消费者。
  • removeQueue:在_vhost中删除队列,同时在消费者管理器中销毁与该队列相关的消费者。
       // 2. 声明/删除 队列
        void declareQueue(const DeclareQueueReqPtr &req)
        {
            //_vhost中添加队列并初始化QueueMsg
            // channel中需要初始化该队列的QueueConsumer
            bool ret = _vhost->declareQueue(req->q_name(),
                                            req->durable(),
                                            req->exclusive(),
                                            req->auto_delete(),
                                            req->args());
            if (!ret)
                return basicCommonResponse(req->rid(), req->chid(), ret);
            _cmp->initQueueConsumer(req->q_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        void removeQueue(const RemoveQueueReqPtr &req)
        {
            //_vhost中移除队列+消息+绑定
            // channel中需要额外移除该队列的QueueConsumer
            bool ret = _vhost->removeQueue(req->q_name());
            if (!ret)
                return basicCommonResponse(req->rid(), req->chid(), ret);
            _cmp->destroyQueueConsumer(req->q_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }

绑定和解绑

绑定和解绑只涉及到交换机,队列和绑定模块,与消费者模块无关,调用_vhost相应接口即可。

      // 3. 绑定/解绑
        void bind(const BindReqPtr &req)
        {
            bool ret = _vhost->bind(req->e_name(), req->q_name(), req->bind_key());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        void unbind(const UnbindReqPtr &req)
        {
            bool ret = _vhost->unbind(req->e_name(), req->q_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }

消息的发布和确认

先从虚拟机中找到对应的交换机和队列,然后根据路由键将消息发布到符合条件的队列中。
每个消息的消费任务会被封装成一个异步任务,提交到线程池中执行

     // 4. 发布/确认 消息到某个队列
        void basicPublish(const BasicPublishReqPtr &req) // 生产者发布消息
        {
            // 1.获取要发布给的交换机的信息
            Exchange::ptr p_exchange = _vhost->selectExchange(req->e_name());
            if (p_exchange.get() == nullptr)
            {
                DLOG("basicPublish: exchange not found %s", p_exchange->_name.c_str());
                return basicCommonResponse(req->rid(), req->chid(), false);
            }
            // 2.获取该交换机绑定的所有队列
            MsgQueueBindingMap queue_bind_map = _vhost->selectByExchange(req->e_name());
            if (queue_bind_map.empty())
            {
                DLOG("basicPublish: queue not found %s", p_exchange->_name.c_str());
                return basicCommonResponse(req->rid(), req->chid(), false);
            }
            // 3.遍历所有队列,进行交换路由,成功则将该发布消息到该队列
            for (auto &kv : queue_bind_map)
            {
                bool ret = Routine::route(p_exchange->_type,
                                          req->attr().routine_key(),
                                          kv.second->_binding_key);
                if (ret)
                {
                    // 将消息添加到队列中(添加消息的管理)
                    _vhost->basicPublish(kv.first, req->mutable_attr(), req->body());

                    // 4.消费者消费该条消息,将消息封装成任务,push到线程池的任务队列并异步执行
                    Consumer::ptr p_consumer = _cmp->choose(kv.first);
                    auto task = std::bind(&Channel::consume, this, kv.first);
                    _pool->push(task);
                }
            }
            return basicCommonResponse(req->rid(), req->chid(), true);
        }

consume函数(消费任务)

实现了某个队列consume一条消息的过程。

    void consume(const std::string &qname)
        {
            // 1.取出一条消息
            msg_ptr msgp = _vhost->basicConsume(qname);
            if (msgp.get() == nullptr)
            {
                DLOG("consume: msg not found %s", qname.c_str());
                return;
            }
            // 2.取出一个消费者
            Consumer::ptr p_consumer = _cmp->choose(qname);
            if (p_consumer.get() == nullptr)
            {
                DLOG("consume: consumer not found %s", qname.c_str());
                return;
            }
            // 3.调用消费者回调函数
            p_consumer->_cb(p_consumer->_tag,
                            msgp->mutable_msg_self()->mutable_basic_attributes(),
                            msgp->msg_self().body());
            // 4.判断是否需要自动ack确认
            if (p_consumer->_auto_ack)
            {
                _vhost->basicAck(p_consumer->_qname, msgp->msg_self().basic_attributes().id());
            }
        }

callback函数(消息处理)

   // 消费者回调函数
        void callback(const std::string &consumer_tag, const msg::BasicAttributes *pbasic,
                      const std::string &body)
        {
            // 1.封装响应消息
            msg::BasicConsumeRsp rsp;
            rsp.set_chid(_chid);
            rsp.set_consumer_tag(consumer_tag);
            std::string tmp_body = "这是消费者回调函数返回的消息: ";
            tmp_body += body;
            rsp.set_body(tmp_body);
            if (pbasic)
            {
                rsp.mutable_attr()->CopyFrom(*pbasic);
            }
            // 2.发送响应消息给客户端
            _codec->send(_conn, rsp);
        }

消息确认

        void basicAck(const BasicAckReqPtr &req)
        {
            _vhost->basicAck(req->q_name(), req->messagg_id());
            return basicCommonResponse(req->rid(), req->chid(), true);
        }

消息订阅与取消订阅

订阅时,检查队列是否存在,然后创建消费者并管理。

取消订阅时,移除队列中的这个消费者。

  // 5. 订阅/解除订阅 某个队列
        void basicSubscribe(const BasicSubscribeReqPtr &req)
        {
            // 消费者用户订阅某一个队列的消息
            // 创建一个消费者给该用户对应的信道里的_consumer,并添加到内存中管理
            // 1.判断队列是否存在
            if (!_vhost->queueExists(req->q_name()))
            {
                DLOG("basicSubscribe: queue not found %s", req->q_name().c_str());
                return;
            }
            // 2.创建消费者并管理
            auto cb = std::bind(&Channel::callback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
            Consumer::ptr consumer = _cmp->create(req->q_name(), req->consumer_tag(), req->auto_ack(), cb);
            _consumer = consumer; // 该信道对应消费者用户
            return basicCommonResponse(req->rid(), req->chid(), true);
        }
        void basicCancel(const BasicCancelReqPtr &req) // 取消订阅
        {
            _cmp->remove(req->q_name(), _consumer->_tag);
            return basicCommonResponse(req->rid(), req->chid(), true);
        }

四.ChannelManager的实现

ChannelManager 类负责管理所有的 Channel 实例,提供了 Channel 的创建、关闭和获取等功能。这个类的设计目的是为了有效管理信道资源,并确保线程安全。

成员变量和方法

class ChannelManager
{
private:
    std::mutex _mutex; // 互斥锁,用于保护_channel的线程安全
    std::unordered_map<std::string, Channel::ptr> _channels; // 存储信道的哈希表

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

    ChannelManager() {}

    bool openChannel(const std::string &chid,
                     const VirtualHost::ptr &vhost,
                     const ConsumerManager::ptr &cmp,
                     const muduo::net::TcpConnectionPtr &conn,
                     const ProtobufCodecPtr &codec,
                     const ThreadPool::ptr &pool);
    
    void closeChannel(const std::string &chid);
    
    Channel::ptr getChannel(const std::string &chid);
};

信道的新增删除获取

  bool openChannel(const std::string &chid,
                         const VirtualHost::ptr &vhost,
                         const ConsumerManager::ptr &cmp,
                         const muduo::net::TcpConnectionPtr &conn,
                         const ProtobufCodecPtr &codec,
                         const ThreadPool::ptr &pool)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(chid);
            if (it != _channels.end())
            {
                DLOG("openChannel:channel already exists %s", chid.c_str());
                return true;
            }
            auto ret = std::make_shared<Channel>(chid, vhost, cmp, conn, codec, pool);
            _channels.insert(std::make_pair(chid, ret));
            DLOG("openChannel:channel created %s", chid.c_str());
            return true;
        }
        void closeChannel(const std::string &chid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(chid);
            if (it == _channels.end())
            {
                DLOG("closeChannel:channel not exists %s", chid.c_str());
                return;
            }
            _channels.erase(it);
        }
        Channel::ptr getChannel(const std::string &chid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(chid);
            if (it == _channels.end())
            {
                DLOG("getChannel:channel not exists %s", chid.c_str());
                return Channel::ptr();
            }
            return it->second;
        }

五.全部代码

#pragma once
#include "../common_mq/helper.hpp"
#include "../common_mq/logger.hpp"
#include "../common_mq/msg.pb.h"
#include "../common_mq/myproto.pb.h"
#include <string>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <cassert>
#include <cstring>
#include "virtual_host.hpp"
#include "consumer.hpp"
#include "proto/codec.h"
#include "muduo/net/TcpConnection.h"
#include "thread_pool.hpp"
#include "routine.hpp"

namespace mq
{
    using ProtobufCodecPtr = std::shared_ptr<ProtobufCodec>;

    using OpenChannelPtr = std::shared_ptr<msg::OpenChannelReq>;
    using CloseChannelReqPtr = std::shared_ptr<msg::CloseChannelReq>;
    using DeclareExchangeReqPtr = std::shared_ptr<msg::DeclareExchangeReq>;
    using RemoveExchangeReqPtr = std::shared_ptr<msg::RemoveExchangeReq>;
    using DeclareQueueReqPtr = std::shared_ptr<msg::DeclareQueueReq>;
    using RemoveQueueReqPtr = std::shared_ptr<msg::RemoveQueueReq>;
    using BindReqPtr = std::shared_ptr<msg::BindReq>;
    using UnbindReqPtr = std::shared_ptr<msg::UnbindReq>;
    using BasicPublishReqPtr = std::shared_ptr<msg::BasicPublishReq>;
    using BasicAckReqPtr = std::shared_ptr<msg::BasicAckReq>;
    using BasicSubscribeReqPtr = std::shared_ptr<msg::BasicSubscribeReq>;
    using BasicCancelReqPtr = std::shared_ptr<msg::BasicCancelReq>;

    class Channel
    {
    private:
        std::string _chid;                  // channel id
        VirtualHost::ptr _vhost;            // 虚拟机的句柄
        Consumer::ptr _consumer;            // 信道关联的消费者
        ConsumerManager::ptr _cmp;          // 消费者管理器
        ProtobufCodecPtr _codec;            // Protobuf协议处理器,对收到的req数据进行协议处理
        muduo::net::TcpConnectionPtr _conn; // tcp连接
        ThreadPool::ptr _pool;              // 线程池
    public:
        using ptr = std::shared_ptr<Channel>;
        Channel()
        {
            DLOG("channel:%p created", this);
        }
        Channel(const std::string &chid,
                const VirtualHost::ptr &vhost,
                const ConsumerManager::ptr &cmp,
                const muduo::net::TcpConnectionPtr &conn,
                const ProtobufCodecPtr &codec,
                const ThreadPool::ptr &pool)
            : _chid(chid),
              _vhost(vhost),
              _cmp(cmp),
              _codec(codec),
              _conn(conn),
              _pool(pool)
        {
            DLOG("channel:%p created", this);
        }
        ~Channel() // 在消费者管理器中移除该消费者
        {
            if (_cmp.get() != nullptr)
            {
                _cmp->remove(_consumer->_qname, _consumer->_tag);
                DLOG("channel:%p destroyed", this);
            }
        }
        // 1. 声明/删除 交换机
        void declareExchange(const DeclareExchangeReqPtr &req)
        {
            bool ret = _vhost->declareExchange(req->e_name(),
                                               req->e_type(), req->durable(),
                                               req->auto_delete(), req->args());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        void removeExchange(const RemoveExchangeReqPtr &req)
        {
            bool ret = _vhost->removeExchange(req->e_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        // 2. 声明/删除 队列
        void declareQueue(const DeclareQueueReqPtr &req)
        {
            //_vhost中添加队列并初始化QueueMsg
            // channel中需要初始化该队列的QueueConsumer
            bool ret = _vhost->declareQueue(req->q_name(),
                                            req->durable(),
                                            req->exclusive(),
                                            req->auto_delete(),
                                            req->args());
            if (!ret)
                return basicCommonResponse(req->rid(), req->chid(), ret);
            _cmp->initQueueConsumer(req->q_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        void removeQueue(const RemoveQueueReqPtr &req)
        {
            //_vhost中移除队列+消息+绑定
            // channel中需要额外移除该队列的QueueConsumer
            bool ret = _vhost->removeQueue(req->q_name());
            if (!ret)
                return basicCommonResponse(req->rid(), req->chid(), ret);
            _cmp->destroyQueueConsumer(req->q_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        // 3. 绑定/解绑
        void bind(const BindReqPtr &req)
        {
            bool ret = _vhost->bind(req->e_name(), req->q_name(), req->bind_key());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        void unbind(const UnbindReqPtr &req)
        {
            bool ret = _vhost->unbind(req->e_name(), req->q_name());
            return basicCommonResponse(req->rid(), req->chid(), ret);
        }
        // 4. 发布/确认 消息到某个队列
        void basicPublish(const BasicPublishReqPtr &req) // 生产者发布消息
        {
            // 1.获取要发布给的交换机的信息
            Exchange::ptr p_exchange = _vhost->selectExchange(req->e_name());
            if (p_exchange.get() == nullptr)
            {
                DLOG("basicPublish: exchange not found %s", p_exchange->_name.c_str());
                return basicCommonResponse(req->rid(), req->chid(), false);
            }
            // 2.获取该交换机绑定的所有队列
            MsgQueueBindingMap queue_bind_map = _vhost->selectByExchange(req->e_name());
            if (queue_bind_map.empty())
            {
                DLOG("basicPublish: queue not found %s", p_exchange->_name.c_str());
                return basicCommonResponse(req->rid(), req->chid(), false);
            }
            // 3.遍历所有队列,进行交换路由,成功则将该发布消息到该队列
            for (auto &kv : queue_bind_map)
            {
                bool ret = Routine::route(p_exchange->_type,
                                          req->attr().routine_key(),
                                          kv.second->_binding_key);
                if (ret)
                {
                    // 将消息添加到队列中(添加消息的管理)
                    _vhost->basicPublish(kv.first, req->mutable_attr(), req->body());

                    // 4.消费者消费该条消息,将消息封装成任务,push到线程池的任务队列并异步执行
                    Consumer::ptr p_consumer = _cmp->choose(kv.first);
                    auto task = std::bind(&Channel::consume, this, kv.first);
                    _pool->push(task);
                }
            }
            return basicCommonResponse(req->rid(), req->chid(), true);
        }
        void basicAck(const BasicAckReqPtr &req)
        {
            _vhost->basicAck(req->q_name(), req->messagg_id());
            return basicCommonResponse(req->rid(), req->chid(), true);
        }
        // 5. 订阅/解除订阅 某个队列
        void basicSubscribe(const BasicSubscribeReqPtr &req)
        {
            // 消费者用户订阅某一个队列的消息
            // 创建一个消费者给该用户对应的信道里的_consumer,并添加到内存中管理
            // 1.判断队列是否存在
            if (!_vhost->queueExists(req->q_name()))
            {
                DLOG("basicSubscribe: queue not found %s", req->q_name().c_str());
                return;
            }
            // 2.创建消费者并管理
            auto cb = std::bind(&Channel::callback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
            Consumer::ptr consumer = _cmp->create(req->q_name(), req->consumer_tag(), req->auto_ack(), cb);
            _consumer = consumer; // 该信道对应消费者用户
            return basicCommonResponse(req->rid(), req->chid(), true);
        }
        void basicCancel(const BasicCancelReqPtr &req) // 取消订阅
        {
            _cmp->remove(req->q_name(), _consumer->_tag);
            return basicCommonResponse(req->rid(), req->chid(), true);
        }

    private:
        // 消费者回调函数
        void callback(const std::string &consumer_tag, const msg::BasicAttributes *pbasic,
                      const std::string &body)
        {
            // 1.封装响应消息
            msg::BasicConsumeRsp rsp;
            rsp.set_chid(_chid);
            rsp.set_consumer_tag(consumer_tag);
            std::string tmp_body = "这是消费者回调函数返回的消息: ";
            tmp_body += body;
            rsp.set_body(tmp_body);
            if (pbasic)
            {
                rsp.mutable_attr()->CopyFrom(*pbasic);
            }
            // 2.发送响应消息给客户端
            _codec->send(_conn, rsp);
        }
        void consume(const std::string &qname)
        {
            // 1.取出一条消息
            msg_ptr msgp = _vhost->basicConsume(qname);
            if (msgp.get() == nullptr)
            {
                DLOG("consume: msg not found %s", qname.c_str());
                return;
            }
            // 2.取出一个消费者
            Consumer::ptr p_consumer = _cmp->choose(qname);
            if (p_consumer.get() == nullptr)
            {
                DLOG("consume: consumer not found %s", qname.c_str());
                return;
            }
            // 3.调用消费者回调函数
            p_consumer->_cb(p_consumer->_tag,
                            msgp->mutable_msg_self()->mutable_basic_attributes(),
                            msgp->msg_self().body());
            // 4.判断是否需要自动ack确认
            if (p_consumer->_auto_ack)
            {
                _vhost->basicAck(p_consumer->_qname, msgp->msg_self().basic_attributes().id());
            }
        }
        void basicCommonResponse(const std::string &rid, const std::string &chid, bool success)
        {
            msg::BasicCommonResponse resp;
            resp.set_rid(rid);
            resp.set_chid(chid);
            resp.set_success(success);
            return _codec->send(_conn, resp);
        }
    };

    class ChannelManager
    {
    private:
        std::mutex _mutex;
        std::unordered_map<std::string, Channel::ptr> _channels;

    public:
        using ptr = std::shared_ptr<ChannelManager>;
        ChannelManager() {}
        bool openChannel(const std::string &chid,
                         const VirtualHost::ptr &vhost,
                         const ConsumerManager::ptr &cmp,
                         const muduo::net::TcpConnectionPtr &conn,
                         const ProtobufCodecPtr &codec,
                         const ThreadPool::ptr &pool)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(chid);
            if (it != _channels.end())
            {
                DLOG("openChannel:channel already exists %s", chid.c_str());
                return true;
            }
            auto ret = std::make_shared<Channel>(chid, vhost, cmp, conn, codec, pool);
            _channels.insert(std::make_pair(chid, ret));
            DLOG("openChannel:channel created %s", chid.c_str());
            return true;
        }
        void closeChannel(const std::string &chid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(chid);
            if (it == _channels.end())
            {
                DLOG("closeChannel:channel not exists %s", chid.c_str());
                return;
            }
            _channels.erase(it);
        }
        Channel::ptr getChannel(const std::string &chid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _channels.find(chid);
            if (it == _channels.end())
            {
                DLOG("getChannel:channel not exists %s", chid.c_str());
                return Channel::ptr();
            }
            return it->second;
        }
    };
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值