A-A+

Cwinux源码解析(五)

2014年01月19日 Linux环境编程 评论 1 条 阅读 991 次
摘要:

介绍Cwinux中关于Reactor模式的具体实现。

在描述了Reactor模式后,本文介绍Cwinux中关于Reactor模式的具体实现。

CwxAppHandler4Base

CwxAppHandler4Base 是Reactor模式中的EventHandler的实现,EventHandle是对CwxAppHandler4Base的封装。其代码如下:

代码中的m_mask是事件掩码(不同位表示读/写/超时/信号等事件)。CwxAppHandler4Base是具体的事件处理者(Handler)。CwxAppHandler4Base的最主要的函数是handle_event函数,该函数用来处理事件。

CwxAppHandler4Base有一个字段m_handle,即文件描述符fd。其中open函数和close函数用于打开和关闭这个fd。handle_event函数,该函数用来处理事件。

CwxAppHandler4Msg

CwxAppHandler4Base是抽象的EventHandler。Reactor模式中的ConcreateEventHandler 包括CwxAppHandler4Msg等。CwxAppHandler4Msg都是从CwxAppHandler4Base继承的子类。该类能够从fd上读取数据,并生成消息对象,或者将消息从网络上发送出去(发送给fd对应的网络连接)。

CwxAppHandler4Msg的handle_event函数实现如下:

代码中m_conn表示连接的属性,其定义如下:

m_conn.getState()返回该连接的状态。handle_event函数中,如果连接的状态是ESTABLISHED,则判断事件掩码,针对写事件和读事件分别调用handle_output()函数和handle_input()函数。

以handle_input()为例,其实现如下(其中删除了错误检查/更新统计量等部分代码):

Cwinux中建立的网络连接上的数据有可能是消息或者是raw data。前者(消息)会由Cwinux来进行接收数据并打包成消息,用户得到的就是一个接收好的消息对象。后者(raw data)指的是这个连接上的数据不是消息,用户要自己读取所有的字节数据并处理。这是连接的两种模式,具体使用哪种模式是在用户建立连接时通过参数指定的。另外,代码中this->getApp()相关的代码是AppFramework相关的内容,我们会在后面解释这些代码。

handle_input实现过程:首先判断该连接是消息模式还是raw data模式。如果是raw data模式,则调用result = this->getApp()->onRecvMsg(*this, bSuspend);函数。该函数会通知用户接收数据(后面详解)。如果是消息模式,则先读取数据,形成一个消息头,然后根据消息头中记录的长度,读取一个完整的消息,并将这个消息放在m_recvMsgData对象中,最后通知用户接收该消息。

handle_output()函数实现如下:

首先从以保存的消息列表中取出一个消息,然后调用nonBlockSend函数发送该消息。nonBlockSend调用CwxSocket::write将消息发送出去。

 

好,先小结一下前面所说的内容:Cwinux中,CwxAppHandler4Base是Reactor模式中的EventHandler,是个父类,它定义了handle_event这样的一个接口。CwxAppHandler4Base派生的子类如CwxAppHandler4Msg在其覆盖(override)的handle_event函数中处理具体的事件。

 

 CwxAppEpoll

CwxAppEpoll是Cwinux中的epoll引擎的封装,同时CwxAppEpoll封装了fd到EventHandle(mask+CwxAppHandler4Base)的映射。

CwxAppEpoll的代码如下(部分):

m_eHandler描述了fd到EventHandle的映射。某个fd上有事件发生,可以查询m_eHandler数组来获得该fd上事件处理handler。registerHandler和resumeHandler等都是维护这个数据结构的函数。另外,CwxAppEpoll除了处理网络连接上的事件之外,还处理了signal的事件和超时事件。超时事件是由m_timeHeap时间堆来维护的。

CwxAppEpoll最重要的函数当然是执行多路分发的poll函数。

poll函数处理了网络连接上的读写等事件、信号signal事件和超时事件(代码经过了简化)。

代码首先处理计算超时时间,tv记录下次超时事件还有多长时间。

然后调用epoll_wait来查询网络连接上是否有事件发生。epoll_wait会等待tv时间,期间如果某些连接上有事件发生,则epoll_wait返回,num记录了有多少连接上有事件发生。当有事件发生时,针对这些连接上的事件执行对应的handle。具体通过callback来执行。

信号处理类似,某些信号发生时,对应位置被置位。检查所有位置,发生信号的话,就执行对应的处理handler。

超时事件通过最小堆来完成,不断地从堆中取出已经超时的handler,执行对应的处理handler。

 

好,先小结一下这段内容:CwxAppEpoll是对epoll的封装,同时维护了fd到EventHandle的映射关系。执行poll函数后,能够检测到网络连接上的事件、信号事件和超时事件,并分别处理。

 

CwxAppReactor

下面看一下Reactor类。

Cwinux中的CwxAppReactor是Reactor模式中Reactor的具体实现。

主要成员变量:

  1. AppEpoll*  m_engine;即一个epoll引擎,通过这个引擎,Reactor监测事件的发生并处理事件。
  2. m_connId[];该数组维护了文件描述符fd到 连接ID(connId,整形)的映射。关于connId,当新的连接建立时,由Cwinux指定一个新的整形数字作为新连接的id。参见代码CwxAppTcpAcceptor::makeHander函数。这样Cwinux就可以从fd直接找到对应的connId,同时已知connId能够通过m_connMap这一数据结构得到fd。
  3. hash_map<ConnIdType,Handler4Base*>  m_connMap;维护了connId到Handler4Base*的映射关系。给定一个connId,Cwinux能够得到对应的Handler4Base*,通过Handler4Base的getHandle()函数可以得到对应的文件描述符fd。

 

主要成员函数包括run和callback函数。

run函数代码如下:

简言之,run函数的代码结构是这样的:

run函数的所有核心工作都是有AppEpoll的poll来完成的。

callback函数也很简单。

简言之,就是执行参数中handler的具体动作(调用handle_event函数)。

 

总结:

对照Reactor模式,看Cwinux中相应的实现:CwxAppHandler4Base 是Reactor模式中的EventHandler的实现,EventHandle是对CwxAppHandler4Base的封装;CwxAppEpoll是多路复用引擎;CwxAppReactor是对应于Reactor模式中的Reactor的实现。此外,CwxAppReactor通过两个数据结构,维护了fd到connId的映射。

 

标签:

1 条留言  访客:0 条  博主:0 条   引用: 1 条

来自外部的引用: 1 条

  • Cwinux源码解析系列 | 薛途的博客

给我留言