LoopJump's Blog

Cwinux简介

2014-01-05

Cwinux是什么

2013年7、8月份,我在腾讯实习的时候,mentor安排我学习cwinux这个开源项目。实习期间阅读了cwinux项目的部分源代码,受益良多,现在写成博客分享交流,欢迎各位读者批评指正。

Cwinux是国人开源的一个Linux下的通信框架,C++语言编写。该框架(架构)内部集成了通信channel、信号处理、时钟处理、日志处理。 可以充分的利用多核的OS。通过此架构,可以方便地开发网络应用。

从这里可以下载源码:

GoogleCode地址:http://code.google.com/p/cwinux/

在OSChina上也有简介:http://www.oschina.net/p/cwinux

源码包里面除源码外,还包含了使用Cwinux的开发指南,一个使用Cwinux的例子和与apache/nginx/C语言的接口等。Cwinux的源码注释和文档非常规范详实,作者值得赞颂。

Cwinux最近一次更新时间是2013年7月份。基于Cwinux框架的其他项目有Unistor(key-value存储系统),cwinux-mq(消息队列)等。我在实习期间阅读的代码是2.3.7版本。本博客针对该版本的Cwinux进行了初步的源码解析,其中部分内容来自Cwinux官方文档。在解析源码之前,首先简单看看Cwinux的用法。这里以echo服务为例。

Cwinux echo例子

Cwinux echo服务实现的功能为:启动服务后,建立监听,客户端向服务器发送一个字符串消息,服务器将该消息返回给客户端。

本文将简单描述Cwinux echo的结构,细节的描述请参考Cwinux开发手册第2章。

echo配置

echo服务的配置文件是xml格式的,CwxEchoConfig类用来解析xml文件,获取配置参数。主要的配置参数包括工作目录,监听IP/Port等。

echo应用类

CwxEchoApp类继承自CwxAppFramework。CwxAppFramework是Cwinux的内置类,代表一个应用。使用Cwinux开发网络服务应用时,用户都要从CwxAppFramework派生一个类,并重载(override)关心的函数。

CwxEchoApp类的代码精简后如下:

1
2
3
4
class CwxEchoApp : public CwxAppFramework{
int initRunEnv();
void onRecvMsg(...);
};

initRunEnv函数初始化运行环境,其代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int CwxEchoApp::initRunEnv(){
/*
设置系统的时钟间隔,最小刻度为1ms,此为1s。
设置工作目录
设置循环运行日志的数量
设置每个日志文件的大小
*/
///调用架构的initRunEnv,使以上设置的参数生效
CwxAppFramework::initRunEnv();

///注册echo请求的处理handle,echo请求的svr-id为SVR_TYPE_ECHO
m_eventHandler = new CwxEchoEventHandler(this);
this->getCommander().regHandle(SVR_TYPE_ECHO, m_eventHandler);

///监听TCP连接,其建立的连接的svr-id都为SVR_TYPE_ECHO,接收的消息的svr-id都为SVR_TYPE_ECHO。全部由m_eventHandler对象来处理
this->noticeTcpListen(SVR_TYPE_ECHO,IP,PORT,MODE...);

///创建线程池对象,此线程池中线程的group-id为2,线程池的线程数量为m_config.m_unThreadNum。
m_threadPool = new CwxThreadPool(..., &getCommander());

///启动线程,线程池中线程的线程栈大小为1M。
m_threadPool->start(NULL));
}

关于Commander: 每个消息都有自己的类型, 每种类型的消息都有一个预设的操作对象来处理这个消息。Cwinux框架中CwxCmdOp类是所有操作对象的父类。代码中的CwxEchoEventHandler就是继承自CwxCmdOp类。Commander可以被视为类型到操作对象的映射关系管理者。代码将SVR_TYPE_ECHO 类型的消息关联到CwxEchoEventHandler并将这个映射关系注册到Commander中,所有SVR_TYPE_ECHO类型的消息都会最终交给C wxEchoEventHandler来处理。

CwxEchoApp要重载该应用所关心的响应函数。响应函数是指框架收到事件通知时执行的处理函数,例如,框架收到消息包时会调用onRecvMsg函数,收到定时器事件时会调用onTime函数,收到信号事件时会调用onSignal函数。echo服务主要关心的是onRecvMsg函数。当echo服务收到消息时,框架会自动调用CwxEchoApp的onRecvMsg函数。开发者只需要重载这个函数,实现自己的业务逻辑(消息处理)就可以。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int CwxEchoApp::onRecvMsg(CwxMsgBlock* msg, CwxAppHandler4Msg& conn, CwxMsgHead const& header, bool& bSuspendConn){
msg->event().setSvrId(conn.getConnInfo().getSvrId());
msg->event().setHostId(conn.getConnInfo().getHostId());
msg->event().setConnId(conn.getConnInfo().getConnId());
msg->event().setIoHandle(conn.getHandle());
msg->event().setConnUserData(NULL);
msg->event().setMsgHeader(header);
msg->event().setEvent(CwxEventInfo::RECV_MSG);
msg->event().setTimestamp(CwxDate::getTimestamp());
///不停止继续接收
bSuspendConn = false;
///将消息放到线程池队列中,有内部的线程调用其处理handle(CwxEchoEventHandler)来处理
m_threadPool->append(msg);
return 0;
}

Cwinux的架构比较复杂,处理了从最底层socket fd上读取并构造消息,创建线程池,分发消息,处理消息,以及更复杂的异步Task。除了整个架构比较复杂外,细节也比较多,例如,建立Tcp监听时有两种模式可选,对应的响应函数不同(一个由框架接收数据生成消息,另一个只是由框架通知有数据到来)。因此,个人以为,在使用Cwinux前最好先对源码有一些了解。

此外,单从学习角度看,Cwinux框架涉及到的Linux环境编程知识覆盖面广,用法典型,文档和注释都非常规范详实,是学习Linux环境编程的一个很好的材料。

扫描二维码,分享此文章