Quantcast
Channel: Vimer的程序世界 »开源
Viewing all articles
Browse latest Browse all 3

有限状态机的C++实现(2)-bayonet开源网络服务器框架

0
0

接着上一篇文章: 有限状态机的C++实现(1)-epoll状态机,我们今天来介绍更复杂和深入的部分。

为什么会在标题中提到bayonet这个开源项目呢?笔者本人一直想要写一套架构优美、功能完善的异步server框架,也看过很多朋友、同事实现的版本,虽然功能上基本能满足需求,但是架构上我却始终觉得是有瑕疵的,直到后来和同事讨论,发现可以让一个客户端请求的到来作为一个session,而之后的每一次与其他server的交互都可以看作是一次状态转化,才感觉架构比较合理了。

简单来说即,一个session从开始到介绍会经历两种状态机的变化:

  • 1.业务逻辑层面的状态变化,例如先验证登录态,再验证权限,再获取用户资料
  • 2.每一个与其他server交互的socket自身的状态变化,如recv、send、等,而socket的状态变化会触发逻辑层的状态变化。

按照这种思路,目前的代码开发已经完成了70%,即可以正常的进行一个session的开始和结束,主要还缺一些细节的代码,比如超时的检测及超时之后的处理,健全的统计之类。好了,我们来用vs看一下代码的整体类图(图压缩比较严重,请单击后查看):

1

每个类的用处已经在途中简单说明了,这里就不再赘述,我们重点来看一下用这个框架来实现一个逻辑server时需要做哪些事情。
svr2目录下的main.cpp即实现了一个最简单的server,我们按部分来看其实现:
1.逻辑层状态的定义

class CAppFsmLogic1 : public CAppFsmBase
{
public:
    virtual ~CAppFsmLogic1 () {}
    virtual int HandleEntry(CActionInfoSet *pActionInfoSet, CAppActorBase* pAppActor)
    {
        static CActionFirst actionFirst;
        StActionInfoParam param;
        param.id = 1;
        param.ip = "127.0.0.1";
        param.port = 100;
        param.protoType = PROTO_TYPE_UDP;
        param.pAction = &actionFirst;
        param.actionType = ACTIONTYPE_SENDONLY;
        param.timeout_ms = 1000;

        CActionInfo * pActionInfo = new CActionInfo();
        pActionInfo->Init(param);
        pActionInfo->SetAppActor(pAppActor);
        pActionInfoSet->Add(pActionInfo);
        return 0;
    }
    virtual int HandleProcess(CActionInfoSet *pActionInfoSet, CAppActorBase* pAppActor)
    {
        trace_log("HandleProcess");
        set<CActionInfo*> &setAction = pActionInfoSet->GetActionSet();
        for(set<CActionInfo*>::iterator it = setAction.begin(); it != setAction.end(); ++it)
        {
            trace_log("error no:%d",(*it)->GetErrno());
        }
        return APP_FSM_RSP;//代表要回复客户端啦
    }
    virtual int HandleExit(CActionInfoSet *pActionInfoSet, CAppActorBase* pAppActor)
    {
        return 0;
    }
};

CAppFsmLogic1是一个逻辑层的状态:

  • 1.HandleEntry代表当这个状态第一次进入的时候要做的事情,其函数中创建了一个向其他server发包的action(CActionFirst的定义我们在后面介绍)。
  • 2.HandleProcess代表当这个状态的所有action都完成时需要做的事情,return APP_FSM_RSP;代表向客户端回包

看到这里大家应该很奇怪,对于每一个socket,判断收包长度以及受到包之后的解包在哪里完成呢?所以我们还需要定义action:
2.action的定义

#define APP_FSM_LOGIC1 2000

class CAppFsmLogic1;
class CActionFirst : public IAction
{
public:
    // 为发送打包
    int HandleEncodeSendBuf(
            IActor* pSocketActor,
            IActor* pAppActor,
            string & strSendBuf,
            int &len)
    {
        trace_log("send");
        strSendBuf="woainizhende111111";
        len = strSendBuf.size();
        return 0;
    }

    // 回应包完整性检查
    int HandleInput(
            IActor* pSocketActor,
            IActor* pAppActor,
            const char *buf,
            int len)
    {
        return len;
    }

    // 回应包解析
    int HandleDecodeRecvBuf(
            IActor* pSocketActor,
            IActor* pAppActor,
            const char *buf, 
            int len)
    {
        CAppActorBase * app_actor = new CAppActorBase();
        app_actor->AttachFrame(pSocketActor->GetFrame());
        app_actor->AttachCommu(pSocketActor);
        app_actor->ChangeState(APP_FSM_LOGIC1);
        trace_log("listen tcp HandleDecodeRecvBuf");
        return 0;
    }
};

每个函数的意义已经在代码中说明了,可以看出在HandleDecodeRecvBuf中创建逻辑层的actor: app_actor,并ChangeState为APP_FSM_LOGIC1。
最后就是main函数的实现了:
3.main函数实现

int main(int argc, const char *argv[])
{
    CBayonetFrame srv;
    StFrameParam param;
    param.ip="0.0.0.0";
    param.port = 10001;
    param.bKeepcnt= true;
    //param.protoType = PROTO_TYPE_UDP;
    param.protoType = PROTO_TYPE_TCP;
    param.pAction = new CActionFirst();

    srv.Init(param);
    srv.RegFsm(APP_FSM_LOGIC1,new CAppFsmLogic1());
    srv.Process();
    return 0;
}

注释的部分是可以随时切换TCP还是UDP的。
当然作为一个server来说,这里还是太过简单了,比如信号的处理等都没有加上,但是笔者认为那是业务代码需要做的逻辑,所以并没有放到框架中。

OK,整个项目的结构就是这个样子了。
但是也不得不说点扫兴的话,由于笔者最近有另外一个项目需要投入大量的精力,所以该项目的更新可能会被延缓,这是我所不愿意看到的,所以很希望有志同道合的朋友能够加入到这个项目的开发中来,一起把这个事情做出来。

按照我当初的想法,压力测试框架fuload已经就绪了,等到bayonet完成,我们就用fuload来测试一下bayonet的性能究竟如何。

最后,附上bayonet的项目地址:
http://code.google.com/p/bayonet/
十分欢迎大家感兴趣的朋友与我联系。


Viewing all articles
Browse latest Browse all 3

Latest Images

Trending Articles





Latest Images