网站挂马检测流程图,ppt模板免费下载哪个网站好,阜阳建设网站,wordpress虚拟机提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 交换机数据管理管理的字段持久化管理类内存管理类申明交换机删除交换机获取指定交换机 队列数据管理管理的字段持久化管理类内存管理类申明/删除/获取指定队列获取所… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 交换机数据管理管理的字段持久化管理类内存管理类申明交换机删除交换机获取指定交换机 队列数据管理管理的字段持久化管理类内存管理类申明/删除/获取指定队列获取所有队列 绑定关系管理管理的字段持久化管理类内存管理类绑定/解除绑定删除指定交换机的所有绑定关系删除队列的所有绑定关系获取指定的队列的所有绑定关系 队列消息管理管理的字段持久化管理类插入消息数据删除消息垃圾回收 队列消息内存管理类管理的字段插入消息删除消息获取队首消息 总的消息内存管理类删除一个队列消息管理新增消息获取队首消息确认消息 数据管理模块需要管理四种数据分别是交换机数据管理/队列数据管理/绑定关系数据管理/队列消息数据管理。
交换机数据管理
管理的字段
需要管理的数据有下面这个5个 交换机名称:交换机的唯一标识 交换机类型交换机有三种类型直接交换/广播交换/主题交换。决定了消息的转发方式。 持久化标识决定了交换机信息是否持久化存储。方便断电后恢复。 剩下的俩个字段不需要关心是为了以后进行扩展的。 struct Exchange
{using ptr std::shared_ptrExchange;std::string name; // 交换机名字ExchangeType type; // 交换机类型bool durable; // 交换机持久化标志位bool auto_delete; // 交换机自动删除标志位 (还未实现该功能)google::protobuf::Mapstd::string, std::string args; // 其他参数 (方便以后扩展)
}持久化管理类
交换机的信息提供了持久化管理的操作我们使用sqlite进行存储。 要管理一个sqlite的操作句柄这个句柄对象也是我们封装了一下sqlite的操作。
在构造函数种需要传入一个文件路径,也就是存储交换机信息的文件。 sqlite是一个本地化的数据库不需要通过网络客户端服务器的模式来进行通信。本地提供一个文件就可以进行存储。一个文件就相当于一个数据库database可以在这个数据库种创建多个表。 我们的交换机/队列/绑定关系信息的数据都是存储在这个文件种的.
class ExchangeMapper
{
private:SqliteHelper _sql_helper; //sqlite句柄
public:ExchangeMapper(const std::string dbfile): _sql_helper(dbfile){// 创建父级目录const std::string path FileHelper::parentDirectory(dbfile);FileHelper::createDirectory(path);// 创建/打开数据库文件assert(_sql_helper.open());// 创建交换机数据表createTable();}
}这就是创建的交换机表。
#define CREATE_TABLE create table if not exists exchange_table(\name varchar(32) primary key, \type int, \durable int, \auto_delete int, \args varchar(128));
bool ret _sql_helper.exec(CREATE_TABLE, nullptr, nullptr);
if (ret false)
{DLOG(创建交换机数据库表失败!!);abort(); // 直接异常退出程序
}这个类还提供一个恢复的接口他会查询交换机表中的所有记录存放到一个哈希表中。
//返回交换机表中所有数据,用于重启后恢复
std::unordered_mapstd::string, Exchange::ptr recovery(){std::unordered_mapstd::string, Exchange::ptr res;std::string sql select name, type, durable, auto_delete, args from exchange_table;_sql_helper.exec(sql, selectCallBack, res);return res;
}内存管理类
在内存管理类中包含了交换机持久化管理类的对象和一个哈希表用来管理已经存在交换机信息。
在他的构造函数中调用了持久化管理的数据恢复接口他会查询数据库表中所有的字段返回一个哈希表也就完成了交换机数据恢复。
//交换机数据内存管理类这个类才是对外提供的
class ExchangeManager
{
private:std::mutex _mutex; //这个类对象可能被多线程访问我们要加锁ExchangeMapper _mapper;std::unordered_mapstd::string,Exchange::ptr _Exchanges; //管理已经存在的交换机ExchangeManager(const std::string dbfile):_mapper(dbfile){//恢复交换机_Exchanges _mapper.recovery();}申明交换机
在rabbitMQ中不叫创建交换机而是叫做申明交换机它是一种强断言的思想代表着存在及ok不存在就创建。这个操作也很简单。 先看看哈希表中存不存在存在就返回true不存在就构建一个交换机对象插入哈希表
bool declareExchange(const std::string name,ExchangeType type, bool durable, bool auto_delete,const google::protobuf::Mapstd::string, std::string args){std::unique_lockstd::mutex lock(_mutex);auto it _Exchanges.find(name);if(it ! _Exchanges.end()){//存在直接returnreturn true;}//定义一个Exchange对象auto ecp std::make_sharedExchange(name,type,durable,auto_delete,args);//插入进数据库if(durable true) {bool ret _mapper.insert(ecp);if(ret false) return false;}_Exchanges.insert({name,ecp});return true;}删除交换机
根据交换机的名称进行一个删除。同时如果持久化存储了也要删除数据库中的数据。
void deleteExchange(const std::string name){std::unique_lockstd::mutex lock(_mutex);auto it _Exchanges.find(name);if(it _Exchanges.end()){return;}//删除数据库中数据if(it-second-durable true){_mapper.remove(name);}_Exchanges.erase(name);}获取指定交换机
根据交换机姓名获取指定交换机。
//获取指定交换机Exchange::ptr selectExchange(const std::string name){std::unique_lockstd::mutex lock(_mutex);auto it _Exchanges.find(name);if(it _Exchanges.end()){//交换机不存在return Exchange::ptr();}return it-second;}队列数据管理
队列和交换机管理的思想几乎一致只不过有些字段不一样
管理的字段
队列名称:队列的唯一标识 持久化标志。 其他字段是扩展字段暂时不关心。 struct MsgQueue{using ptr std::shared_ptrMsgQueue;std::string name; // 队列名称bool durable; // 持久化标志位bool exclusive; // 是否独占 还未实现此功能bool auto_delete; // 自动删除 未实现google::protobuf::Mapstd::string, std::string args; // 其他参数
}持久化管理类
和交换机一样这里看一看表结构
void createTable(){std::stringstream sql;sql create table if not exists queue_table(;sql name varchar(32) primary key, ;sql durable int, ;sql exclusive int, ;sql auto_delete int, ;sql args varchar(128));;assert(_sql_helper.exec(sql.str(), nullptr, nullptr));}内存管理类
都是一个持久化句柄一个哈希表存储已经存在的队列信息。
class MsgQueueManager{private:std::mutex _mutex;MsgQueueMapper _mapper;std::unordered_mapstd::string, MsgQueue::ptr _msg_queues;public:using ptr std::shared_ptrMsgQueueManager;MsgQueueManager(const std::string dbfile) : _mapper(dbfile){//从数据库中读取恢复队列数据_msg_queues _mapper.recovery();}
}申明/删除/获取指定队列
这里不过多介绍都是一样的操作
获取所有队列
但是队列这边提供了一个额外的操作获取所有队列信息。 这里直接构造一个哈希表返回。 我们的队列消息和消费者都是以队列为单元进行管理的。所以我们需要获取到已经存在队列用来初始化队列消息和消费者管理。 //返回所有队列
std::unordered_mapstd::string, MsgQueue::ptr AllQueue(){std::unique_lockstd::mutex lock(_mutex);return _msg_queues; //这里构造了一个}绑定关系管理
管理的字段
交换机名称和队列名称还有一个binding_key。 struct Binding
{using ptr std::shared_ptrBinding;std::string exchange_name; // 交换机名称std::string msgqueue_name; // 队列名称std::string binding_key;
}持久化管理类
绑定关系也是需要持久化管理的。当交换机和队列的持久化标志位都为true时我们才将绑定关系持久化管理。这在虚拟机管理模块进行判断。
void createTable(){std::stringstream sql;sql create table if not exists binding_table(;sql exchange_name varchar(32), ;sql msgqueue_name varchar(32), ;sql binding_key varchar(128));;assert(_sql_helper.exec(sql.str(), nullptr, nullptr));}内存管理类
内存管理类这块也是一个持久化管理句柄。 但是我们这里是交换机和队列的一个信息管理。 因为一个交换机可以绑定多个队列而队列和绑定关系是一一对应的。 所以我们定义了两个类型一个是队列和绑定的映射。一个是交换机和队列绑定的映射。我们实际管理的就是这个交换机和队列绑定的对象。
using MsgQueueBindingMap std::unordered_mapstd::string, Binding::ptr;
using BindingMap std::unordered_mapstd::string, MsgQueueBindingMap;class BindingManager{private:std::mutex _mutex;BindingMapper _mapper;BindingMap _bindings;using ptr std::shared_ptrBindingManager;BindingManager(const std::string dbfile) : _mapper(dbfile){_bindings _mapper.recovery();}
}绑定/解除绑定
需要提供交换机名和队列名称以及binding_key和是否持久化。 这里的是否持久化是虚拟机判断后传入的。 这里也是存在及ok,不存在就创建的思想。
bool bind(const std::string ename, const std::string qname, const std::string key, bool durable){std::unique_lockstd::mutex lock(_mutex);auto eit _bindings.find(ename);if (eit ! _bindings.end() (eit-second.find(qname) ! eit-second.end())){ //绑定数据已存在return true;}Binding::ptr bp std::make_sharedBinding(ename, qname, key);// 当交换机和队列的持久化标志位都为true,绑定数据才进行持久化,这个durable由外界判断后传入if (durable true){bool ret _mapper.insert(bp);if (ret false){return false;}}//存在及获取不存在及创建auto MsgQueueMap _bindings[ename];MsgQueueMap.insert({qname, bp});return true;}删除绑定关系一个交换机可以绑定多个队列这里删除的只是一个交换机和队列的绑定关系。
void unbind(const std::string ename, const std::string qname){std::unique_lockstd::mutex lock(_mutex);auto eit _bindings.find(ename);//没有交换机信息直接退出if(eit _bindings.end()) { return; }auto qit eit-second.find(qname);//没有队列相关信息直接退出if(qit eit-second.end()){ return ;}//判断持久化太麻烦了,所以这里不管持久化标志是否存在,我们直接去数据库中删除_mapper.remove(ename,qname);_bindings[ename].erase(qname);}删除指定交换机的所有绑定关系
当交换机被删除时需要删除该交换机的所有绑定关系
//删除指定交换机的所有绑定数据 ---当删除交换机时需要删除交换机相关的所有绑定信息
void removeExchangeBindngs(const std::string ename){//同样的这里不判断持久化直接操作_mapper.removeExchangeBindings(ename);auto eit _bindings.find(ename);if(eit _bindings.end()){//不存在直接returnreturn;}_bindings.erase(eit);
}删除队列的所有绑定关系
当队列被删除后需要删除该队列所有的绑定关系。 删除的方法就是遍历所有的交换机因为一个队列是可以被多个交换机绑定的。 void removeMsgQueueBindings(const std::string qname){std::unique_lockstd::mutex lock(_mutex);//同样的这里不判断持久化直接操作_mapper.removeMsgQueueBindings(qname);//遍历所有的交换机因为一个交换机可以绑定多个队列这个要删除的队列可能绑定了多个交换机for(auto eit _bindings.begin(); eit ! _bindings.end(); eit){//eit-second是一个MsgQueueMap,这里判断的是这个队列是否存在这个map中存在就删除auto qit eit-second.find(qname);if(qit ! eit-second.end()){eit-second.erase(qit);}}
}获取指定的队列的所有绑定关系
这个接口非常重要当交换机收到信息后我们需要获取该交换机的所有绑定的队列用来判断需要将消息转发到哪个队列。
//获取交换机绑定的队列描述信息当交换机收到消息时需要将消息转给绑定的队列MsgQueueBindingMap getExchangeBindings(const std::string ename){std::unique_lockstd::mutex lock(_mutex);auto eit _bindings.find(ename);if (eit _bindings.end()) {return MsgQueueBindingMap();}return eit-second; }队列消息管理
管理的字段
这个模块有一些复杂,消息是需要被传输的因此我们定义在了proto中我们先看一下消息类型.
消息分为消息属性和消息正文。 消息属性中有三个字段分别是消息的ID,routing_key和持久化模式。 消息正文就是一个string字段。 还有一个消息是否有效标志位。 也就是消息属性消息正文消息是否有效这三个字段是需要持久化存储的。我们把它定义为Payload字段。 其他两个字段是方便服务器进行管理二添加的字段。
//消息属性
message BasicProperties {string id 1; //消息IDstring routing_key 2; //与binding_key做匹配DeliveryMode delivery_mode 3; //持久化模式 1-⾮持久化 2-持久化
};//消息结构
message Message {message Payload {BasicProperties properties 1; //消息属性string body 2; //有效载荷数据string valid 3; //消息是否有效位};Payload payload 1; //真正持久化的只有这⼀个字段uint64 offset 2; //这两个字段⽤于记录消息在持久化⽂件中的位置和⻓度uint64 length 3; //以便于在加载时可以在指定位置读取指定⻓度的数据获取到消息
};持久化管理类
同样的消息也是需要进行持久化的但是消息的持久化我们不是放在数据库中而是存储在文件中。 因为有些消息会很大不适合放在数据库。其次我们只是为了备份不涉及到查询。
另外的我们的消息是以队列为单元进行管理的。
这是消息进行持久化管理的类他有三个成员一个是队列名称另外两个是持久化数据文件的文件名。文件名就是用队列名加上.mqd后缀。 例如qname.mqd这里还有一个tmpfile原因是我们垃圾回收不是在源文件直接操作而是遍历源文件提取出有效消息存入临时文件最后在更改临时文件名称覆盖源文件。 class MessageManpper{private:std::string _qname; // 队列名称std::string _datafile; // 保存消息持久化数据文件std::string _tmpfile; // 垃圾回收时的临时文件}插入消息数据
当收到一个消息后如果消息的持久化标志位true就需要对消息进行持久化存储了。 调用虚拟机的消息发布接口然后调用到队列消息总的内存管理类。然后调用具体的一个队列消息管理类中的插入接口进行插入。如果消息的持久化标志位是true就需要持久化。
bool insert(MessagePtr msp)
{insert(_datafile, msp);
}需要传入一个Message对象这个对象是在队列消息管理的插入接口构造的. 这里的大致流程将消息结构中的Payload结构序列化然后获取到文件的大小也就是我们要要存入的偏移量在偏移量的位置先写入4字节的消息大小也就是Payload的大小然后写入序列化的数据。 最后会把偏移量和消息大小设置到MessagePtr中这个Ptr会存储到消息链表和持久化哈希表中也就同步跟新到内存了。 这里的偏移量是跳过4字节的也就是指向的Payload。
bool insert(const std::string file, MessagePtr msp)
{// 将消息数据中的有效载体序列化std::string body msp-payload().SerializeAsString();FileHelper helper(file);size_t fsize helper.size();size_t msg_size body.size();// 往文件写入4字节数据长度bool ret helper.write((char *)msg_size, fsize, sizeof(size_t));if (ret false){DLOG(往队列文件 %s 写入数据长度失败, file.c_str());return false;}// DLOG(往队列文件 %s 写入数据长度%d,file.c_str(),msg_size);// 往文件写入消息有效载荷ret helper.write(body.c_str(), fsize sizeof(size_t), msg_size);if (ret false){DLOG(往队列文件 %s 写入数据主体失败, file.c_str());return false;}// DLOG(往队列文件 %s 写入数据%d,file.c_str(),body.c_str());// 更改消息数据的偏移量和长度msp-set_offset(fsize sizeof(size_t));msp-set_length(msg_size);return true;
}删除消息
当消息被确认后就需要从文件中删除消息。而删除不是从文件中真的删除而是将消息的有效位置0后覆盖掉原文件中的消息。
这里需要传入一个MessagePtr这个ptr就是收到了消费客户端的确认应答后根据消息id在待确认哈希中找到对应的MessaePtr对象. 如果这个对象的持久化标志位1就需要删除文件中的数据。 删除的流程就是将MessagePtr中的有效位置0然后根据偏移量和消息长度进行一个覆盖写入。 bool remove(MessagePtr msp)
{// 将消息数据的有效位设置位0msp-mutable_payload()-set_valid(0);// 对msg进行序列化std::string body msp-payload().SerializeAsString();if (body.size() ! msp-length()){DLOG(不能修改文件中的数据信息因为新生成的数据与原数据长度不一致!);return false;}FileHelper helper(_datafile);// 将消息数据覆盖写入到文件位置bool ret helper.write(body.c_str(), msp-offset(), body.size());if (ret false){DLOG(向队列数据文件 %s 写入数据失败, _datafile);return false;}return true;
}垃圾回收
这个垃圾回收会返回一个MessagePtr的链表他会从文件中循环读取消息。先算出文件的大小从0偏移量开始读取先读取4字节消息长度然后根据长度读取消息payload,盘后反序列化出一个Payload结构判断有效位是否为1为1则插入到链表中。循环结束就可以得到有效消息的链表。 然后将有效消息写入到临时文件在写入到临时文件中消息的偏移量发生了改变在内存中也存储了消息对象所以需要同步更新消息的偏移量所以我们的返回值是一个MessagePtr的链表。队列消息管理在进行了垃圾回收后可以进行跟新偏移量。
std::listMessagePtr gc()
{std::listMessagePtr result;bool ret load(result);if (ret false){DLOG(加载有效数据失败\n);return result;}// DLOG(加载有效数据结束,数据个数:%d,result.size());// 将有效数据写入临时文件FileHelper::createFile(_tmpfile); //必须先创建出临时文件在datafile中没有数据时不会进这个循环。会导致文件源文件被删除tmp文件也没了FileHelper tmp_file_helper(_tmpfile);size_t offset 0;for (auto msp : result){ret insert(_tmpfile, msp);if (ret false){DLOG(向临时文件写入消息数据失败);return result;}}// DLOG(像临时文件写入数据结束,临时文件大小:%d,tmp_file_helper.size());ret FileHelper::removeFile(_datafile);if (ret false){DLOG(删除源文件失败);return result;}// 4. 修改临时文件名为源文件名称ret FileHelper(_tmpfile).rename(_datafile);if (ret false){DLOG(修改临时文件名称失败);return result;}// 5. 返回新的有效数据return result;
}队列消息内存管理类
队列消息是以队列为单元进行管理的所以这个类是存在一个队列就要有一个。 和交换机/队列/绑定关系不同这里复杂一些.
管理的字段
需要有一个持久化句柄消息需要持久化。 然后一个队列名该类所代表的队列。 一个有效消息数量和总消息数量。用来进行垃圾回收 一个待推送消息链表收到消息后插入这个链表中。 一个持久化哈希表用来垃圾回收后更新内存中消息的偏移量 一个待确认哈希表当消息推送消费者后需要把消息从带推送链表中删除然后插入到待确认哈希表中。
class QueueMessage
{
private:MessageManpper _manpper; //持久化操作的句柄std::string _qname; // 队列名size_t _valid_count; // 有效消息数量size_t _total_count; // 消息总数量std::mutex _mutex;std::listMessagePtr _msgs; // 带推送消息std::unordered_mapstd::string, MessagePtr _durable_msgs; // 持久化消息std::unordered_mapstd::string, MessagePtr _waitack_msgs; // 待确认消息
}插入消息
插入消息是在服务器收到消息发布请求后通过虚拟机句柄调用的我们这里需要构造一个MEssagePTr.用户的请求中可能没有填入消息属性。如果没有填入的话我们就构造一个属性字段填入其中消息ID自动生成持久化标志看队列是否持久化routing_ket设置为空字符串。
bool insert(const BasicProperties *bp, std::string body, bool queue_is_durable)然后我们根据持久化标志位,将消息持久化存储同时更新消息数量然后插入进带推送消息链表中。
删除消息
是在客户端确认后删除待确认哈希表中的消息。 如果消息时持久化的需要删除持久化信息同同时删除消息数量。 另外进行一次垃圾回收垃圾回收需要满足总体消息数量达到2000条且有效消息数量的个数不到总消息的%50 垃圾回收就是调用持久化管理的gc接口它会返回一个list MessagePtr通过这个list跟新内存消息的偏移量(遍历listfind查找持久化哈希表中的Message,进行更新)。同时更新消息数量。 void gc()
{if (GCCheck() false)return;// 获取有效消息std::listMessagePtr msgs _manpper.gc();//这里构造了一个listMessagePtr他和我们的_durable_msgs中的MessagePtr是不同的所以需要单独更改_durable_msgs中MessagePtr的偏移量for (auto msg : msgs){auto it _durable_msgs.find(msg-payload().properties().id());if (it _durable_msgs.end()){// 持久化文件中的消息在内存中不存在DLOG(垃圾回收后有一条持久化消息在内存中没有进行管理);_msgs.push_back(it-second); // 做法将该消息插入进待推送链表的末尾_durable_msgs.insert({msg-payload().properties().id(), msg});continue;}// 更新每一条消息的实际存储位置it-second-set_offset(msg-offset());it-second-set_length(msg-length());}// 3. 更新当前的有效消息数量 总的持久化消息数量_valid_count _total_count msgs.size();
}获取队首消息
当队列收到一个消息就需要进行推送删除消息链表的头部消息然后插入到待确认哈希表中。 // 获取队首消息
MessagePtr front()
{std::unique_lockstd::mutex lock(_mutex);if(_msgs.size() 0){return MessagePtr();}// 从待推送链表中取出一个消息MessagePtr msp _msgs.front();_msgs.pop_front();// 并将该消息添加进待确认哈希表_waitack_msgs.insert({msp-payload().properties().id(), msp});return msp;
}总的消息内存管理类
一个文件路径我们的消息持久化文件的路径。 一个哈希表队列名称和队列消息管理类的映射。 我们对外提供的就是这个对象。 class MessageManager
{
private:std::string _basedir; //存储队列信息文件的路径我们的队列信息是存储在文件中的std::mutex _mutex;std::unordered_mapstd::string, QueueMessage::ptr _queue_msgs; //队列名对应队列信息
}
在他的构造中我们需要根据已经存在的队列创建出队列消息管理类。然后进行一个持久化消息的恢复。
// 初始化一个队列消息管理,在创建队列的时候调用
void InitQueueMessage(const std::string qname)
{QueueMessage::ptr tmp;{std::unique_lockstd::mutex lock(_mutex);auto it _queue_msgs.find(qname);if (it ! _queue_msgs.end()){//DLOG(消息管理句柄 %s 已经存在, qname.c_str());return;}// 构建一个队列消息内存管理类对象QueueMessage::ptr qmp std::make_sharedQueueMessage(_basedir, qname);tmp qmp;_queue_msgs.insert(std::make_pair(qname, qmp));}// 恢复历史数据这个操作是非常耗时的我们没有放在加锁里。tmp-recovery();
}这里不想交换机队列和绑定关系的恢复那么轻量这里的消息数量会很大因此我们没有在队列消息的构造函数中进行而是单独提供了一个接口用来进行恢复。 恢复就是进行一次垃圾回收然后返回一个链表遍历链表插入到内存管理中。
删除一个队列消息管理
当一个队列删除时他的队列消息管理也就没有意义了需要删除他的管理同时删除对应的持久化文件数据。
// 销毁一个队列消息管理在删除队列的时候调用void DestoryQueueMessage(const std::string qname){QueueMessage::ptr tmp;{std::unique_lockstd::mutex lock(_mutex);auto it _queue_msgs.find(qname);if (it _queue_msgs.end()){DLOG(消息管理句柄 %s 不存在, qname.c_str());return;}tmp it-second;_queue_msgs.erase(qname);}tmp-clear();}新增消息
这里都是对指定队列消息管理进行的操作。接口我们已经实现了就是从哈希表中找到 指定的对象就行。
// 新增一条消息bool insert(const std::string qname, BasicProperties *bp, std::string body, bool queue_is_durable)
{QueueMessage::ptr tmp;{std::unique_lockstd::mutex lock(_mutex);auto it _queue_msgs.find(qname);if (it _queue_msgs.end()){DLOG(向队列%s新增消息失败:没有找到消息管理句柄!, qname.c_str());return false;}tmp it-second;}return tmp-insert(bp, body, queue_is_durable);
}获取队首消息 MessagePtr front(const std::string qname)
{QueueMessage::ptr tmp;{std::unique_lockstd::mutex lock(_mutex);auto it _queue_msgs.find(qname);if (it _queue_msgs.end()){DLOG(向队列%s获取队首消息失败:没有找到消息管理句柄!, qname.c_str());return MessagePtr();}tmp it-second;}return tmp-front();
}确认消息 void ack(const std::string qname, const std::string msg_id)
{QueueMessage::ptr tmp;{std::unique_lockstd::mutex lock(_mutex);auto it _queue_msgs.find(qname);if (it _queue_msgs.end()){DLOG(向队列%s确认消息失败:没有找到消息管理句柄!, qname.c_str());return;}tmp it-second;}tmp-remove(msg_id);return;
}