31.4. 适配ACE_Message_Queue
我最近参与了一些关于“中间件路由服务”的商业网络项目,为满足项目需求,我花费了一番心血,将自适配通信环境(Adaptive Communications Environment,ACE)的内存队列适配到STL的集合概念,其成果将由本章涵盖。在使用ACE Reactor框架之前,你需要从ACE_Event_Handler派生出事件处理器类(覆盖相关的事件处理方法),然后将其实例注册到程序的ACE_Reactor单件(singleton)实例中。一旦ACE_Reactor实例接收到I/O事件,并且事件对应的处理器实例已经注册,它就调用后者的恰当回调方法。在搭配TCP——面向流的互联网传输协议——使用的情况下,ACE的惯用法是:用ACE_Message_Block实例保存接收到的数据,然后在类模板ACE_Message_Queue(的某个特化)实例中排队,如清单31.5所示(简洁起见,省去错误处理)。
清单31.5. ACE Reactor框架中的一个简单事件处理器
class SimpleTCPReceiver : public ACE_Event_Handler { . . . virtual int handle_input(ACE_HANDLE h) { const size_t BLOCK_SIZE = 1024; ACE_Message_Block* mb = new ACE_Message_Block(BLOCK_SIZE); ssize_t n = m_peer.recv(mb->base(), mb->size()); mb->wr_ptr(n); m_mq.enqueue_tail(mb); return 0; } . . . private: // Member Variables ACE_SOCK_Stream m_peer; // Connection socket ACE_Message_Queue<ACE_SYNCH_USE> m_mq; // Message queue }; |
ACE_Message_Queue类扮演了一个仓库,所有块在其中按序存放,因此忠实地表达了原始数据流。但ACE_Message_Queue又是一个严格意义的块容器;它不提供任何抽象手段访问块的内容,而是借助相关联的ACE_Message_Queue_Iterator类模板进行遍历,如清单31.6所示。如果容器中的下一个块可用,ACE_Message_Queue_Iterator::next()方法返回非0结果,并设置所传入指针的指向;反之则直接返回0。advance()方法把当前遍历位置移动到下一个块(如果有的话)。
清单31.6. 使用ACE_Message_Queue_Iterator 的示例代码
void SimpleTCPReceiver::ProcessQueue() { ACE_Message_Queue_Iterator<ACE_NULL_SYNCH> mqi(m_mq); ACE_Message_Block* mb; for(; mqi.next(mb); mqi.advance()) { { for(size_t i = 0; i < mb->length(); ++i) { printf("%c", i[mb->rd_ptr()]; }} mb->rd_ptr(mb->length()); // Advance read ptr to "exhaust" block } } |
很显然,如果你想把多个块当作逻辑上连续的单个块来处理,情况就会变得有点混乱。我们需要一个序列来“平整”流,使其适宜于STL的操纵手法。
【责任编辑:
董书 TEL:(010)68476606】