Windows平台下高性能并发服务引擎设计(一)

来源:互联网 发布:小精灵字幕软件下载 编辑:程序博客网 时间:2024/05/16 09:25

 

一、系统内核设计框架图

图示为一个简单的引擎设计草图,最顶层为用户应用开发层,是整个服务引擎的唯一对外接口(直接开放给用户层,由用户层自定义开发),整套服务引擎的设计理念是采用事件驱动模式,本篇主要从该框架图入手简要介绍我所设计的后台服务引擎,后续篇章中我会对每个环节进行详细介绍。

该套引擎在我的程序中被称为IApplication,它包括系统日志接口,定时器接口,session管理器,虚拟服务器列表管理,当前虚拟虚拟目录等。

系统的设计约定如下:

底层系统只关心底层的设计和开发,系统底层的安全由底层自己负责,但是用户层在开发自定义应用的时候,必须接受底层给出的约定,这些技术约定会在后期的开放接口中给与说明,用户层自己的安全由用户层自己负责,底层不做考虑。

事件驱动模型设计:

内核层系统驱动采用iocp(windows平台下完成端口)来实现,由事件驱动概念引申出的io驱动以及定时器驱动都是基于该机制上实现。

Io模型设计:

Io的读写事件有io驱动层来完成,图中将io句柄单独拎出来考虑,主要是因为考虑到以下几点:

        Io多样性(TCP、udp、文件io、管道等)。

        扩展性。

        灵活性,支持多样性io,内核以及用户层不用关心io的实现,仅仅需要关心io能实现的功能,并且能够根据实际需求选择不用io模型。

会话机制:

    会话是服务器端用来标识客户端根服务器之间的联系,每一个客户端可以跟服务器之间同时进行多个通话如果有必要。

 

定时器:

每个虚拟器都有自己的一套定时器驱动,由内核实现,用户层可见,并可按照约定使用定时器

 

二、用户层开发接口

class IGooInterface

{

public:

    virtual ~IGooInterface(){};

 

    /*

     * 函数名称: Init

     * 函数功能: 初始化

     * 参数: application

     * 初始化成功返回true,否则返回false

     */

    virtual bool Init(IApplication& application) = 0;

 

    /*

     * 函数名称: Uninit

     * 函数功能: 销毁

     * 参数: application

     * 初始化成功返回true,否则返回false

     * 注意销毁时主程序忽略该函数返回,返回值留待扩展测试使用

     */

    virtual bool Uninit(IApplication& application) = 0;

 

public:

    /*

     * 函数名称: OnTimer

     * 函数功能: 定时器回调函数

     * 参数: application

     * 参数[handle]: 当前定时器句柄,注意定时器触发时,已经从定时器队列中移出了,用户无需使用该句柄从定时器中再次移出

     * 参数[eventid]: 定时器id

     * 参数[wparam]: 定时器回调参数

     * 参数[lparam]: 定时器回调参数

     * 初始化成功返回0,否则返回-1

     */

    virtual int OnTimer(IApplication& application, const GooTmHandle& handle, unsigned long eventid, void* wparam = NULL, void* lparam = NULL) = 0;

 

    /*

     * 函数名称: GetPkgLen

     * 函数功能: 获取接受数据包包长

     * 参数: application

     * 参数[buffer]: 接受缓存

     * 参数[dat_len]: 数据报长度

     * 参数[isclient]: 是否客户端传来数据报

     * 初始化成功返回>=0,否则返回-1

     */

    virtual size_t GetPkgLen(IApplication& application, const unsigned char* buffer, const size_t& dat_len, bool isclient) = 0;

 

    /*

     * 函数名称: OnReceive

     * 函数功能: 每当引擎成功接收一个数据报后,调用该函数.

     * 参数: application

     * 参数[session]: 用户会话

     * 参数[buffer]: 数据报

     * 参数[isclient]: 是否客户端传来数据报

     * 初始化成功返回=0,否则返回-1

     */

    virtual int OnReceive(IApplication& application, IGooSession* session, const IGooBuffer& buffer, bool isclient) = 0;

 

    /*

     * 函数名称: OnFinish

     * 函数功能: 每当引擎成功发送一个数据报后,调用该函数.

     * 参数: application

     * 参数[session]: 用户会话

     * 参数[buffer]: 数据报

     * 初始化成功返回=0,否则返回-1

     */

    virtual int OnFinish(IApplication& application, IGooSession* session, const IGooBuffer& buffer) = 0;

 

    /*

     * 函数名称: OnClose

     * 函数功能: 用户会话断开,可能是因为超时

     * 参数: application

     * 参数[session]: 用户会话

     * 参数[isclient]: 是否客户端传来数据报

     * 初始化成功返回=0,否则返回-1

     */

    virtual int OnClose(IApplication& application, IGooSession* session, bool isclient) = 0;

};

 三、虚拟服务器设计

class IApplication

{

public:

    virtual ~IApplication(){}

public:

    /*!

     * 函数名称: GetWorkPath

     * 函数功能: 服务器工作路径

     * 注    意: 该接口非线程安全

     */

    virtual const TCHAR* GetWorkPath() const = 0;

 

    /*!

     * 函数名称: GetCurrentServerId

     * 函数功能: 返回服务器唯一标志符

     * 注    意: 该接口非线程安全

     */

    virtual unsigned short GetCurrentServerId() const = 0;

 

    /*!

     * 函数名称: GetSessionManager

     * 函数功能: session容器

     * 注    意: 该接口非线程安全

     */

    virtual IGooSessionManager& GetSessionManager() = 0;

 

    /*!

     * 函数名称: GetConfig

     * 函数功能: 系统配置读取接口

     * 注    意: 该接口非线程安全

     */

    virtual IGooConfig& GetConfig() = 0;

 

    /*!

     * 函数名称: GetServerManager

     * 函数功能: 服务器信息管理

     * 注    意: 该接口线程安全

     */

    virtual IGooServerManager& GetServerManager() = 0;

 

    /*!

     * 函数名称: GetLog

     * 函数功能: 系统日志接口

     * 注    意: 该接口非线程安全

     */

    virtual IGooLog& GetLog() = 0;

 

    /*!

     * 函数名称: GetTimer

     * 函数功能: 用户层定时器接口

     * 注    意: 该接口非线程安全,该接口为用户定时器,用户层可以回调

     */

    virtual IGooTimer& GetTimer() = 0;

 

    /*!

     * 函数名称: Release

     * 函数功能: 释放资源

     * 注    意: 该接口非线程安全

     */

    virtual void Release() = 0;

};

 

Window平台下服务引擎设计我采用的是多线程设计模式,关于线程池的管理非常的简单,这里就不多费笔墨,我们仅讨论虚拟服务器的设计。

通过开放给用户层接口,我们可以发现,系统内核层每次回调用户接口的时候都回传入一个IApplication对象,该对象是虚拟服务器的全局信息,其中包括的主要功能我们可以通过上面代码注释了解。

 

四、定时器驱动设计

class IGooTimer

{

public:

    virtual ~IGooTimer(){}

public:

    /*!

     * 函数名称: Register

     * 函数功能: 注册定时器

     * 参数[eventid]: 定时器id

     * 参数[tm_split]: 每个几秒钟触发一次,注意我们系统的定时器只能精确到秒

     * 参数[wparam]: 定时器触发回调参数

     * 参数[lparam]: 定时器触发回调参数

     * 函数返回: 注册失败返回INVALID_TM_HANDLE, 否则返回值大于0,注意 0 为系统保留

     */

   virtual GooTmHandle Register(unsigned long eventid, const time_t& tm_split, void* wparam = NULL, void* lparam = NULL) = 0;

 

    /*!

     * 函数名称: UnRegister

     * 函数功能: 注销指定定时器

     * 参数[handle]: 定时器句柄

     */

    virtual void UnRegister(const GooTmHandle& handle) = 0;

 

    /*!

     * 函数名称: LoopTimer

     * 函数功能: 定时器主体函数

     * 参数[usr_interface]: 用户层钩子函数,当有定时器触发时调用该接口中的OnTimer接口

     * 注    意: 该函数由系统内核层调用,用户层无需调用该接口

     */

    virtual time_t LoopTimer(IGooInterface* callback) = 0;

 

    /*!

     * 函数名称: Clear

     * 函数功能: 清除所有定时器

     */

    virtual void Clear() = 0;

};

    我想各位开代码就该了解了定时器的所有功能,有windows编码习惯的人,可以将Register理解为SetTimer,UnRegister理解为KillTimer。

    每次注册返回一个定时器句柄,本来想根据windows的设计习惯,返回值直接采用参数eventid,作为返回,但是考虑到一个因素就是,一个虚拟服务器下,可能存在多个会话有注册了eventid定时器服务器,这是考虑到每个事件必须具有唯一性的原理,我们采用内核层自动生成一个句柄来标志定时器事件的唯一性,而不是用过参数eventid来标识事件的唯一性,这样做的好处就是用户层在做编码设计时具有足够的灵活性。

    这里需要注意的是LoopTimer接口,正常情况下由内核层调用,用户层无需关心,每当事件驱动促发时,就调用一下该接口,同时回调用户层接口,并返回下一个定时器促发需要等待时间,所以用户层在调用该接口是须慎用。后期会考虑在IGooTimer上再做一层继承把LoopTimer给隐藏到内核层,这样用户层即便存在无用的可能,也看不到该接口。

 

五、io模型设计

class IGooIOHandle

{

public:

   virtual ~IGooIOHandle(){}

 

public:

   virtual int Read(IGooBuffer& buffer, int offset, int len) = 0;

   virtual int Write(const IGooBuffer& buffer, int offset, int len) = 0;

 

   virtual int RegisterCompletionFunction(LPWSAOVERLAPPED_COMPLETION_ROUTINE fun) = 0;

   virtual OVERLAPPED* GetOverLappedHandle() = 0;

   virtual int Close();

};

 

上面的代码没有注释,但是我想熟悉window编码的人,都该了解大致意思了,这套作接口有一个优化方案,目前在做灵活性测试,到时候会给出一个最终版本的iohandle模型接口。

六、会话(session)模型设计

   class IGooSession

{

public:

        virtual ~IGooSession(){}

public:

        virtual bool IsValid() const = 0;

        virtual SOCKET GetHandle() const = 0;

        virtual unsigned __int64 GetUniqueID() const = 0;

        virtual bool IsTimeout() const = 0;

        virtual size_t GetRestSlip() const = 0;

        virtual void Refresh() = 0;

   

        virtual IGooBufferQueue* GetRecvBufferList() = 0;

        virtual IGooBufferQueue* GetSendBufferList() = 0;

        virtual int PostRecv() = 0;

        virtual int PostSend() = 0;

        virtual void Close() = 0;

};

  

class IGooSysSession : public IGooSession

{

public:

    virtual ~IGooSysSession(){}

public:

    virtual GOO_OVERLAPPED* GetWriteLapped() = 0;

    virtual GOO_OVERLAPPED* GetReadLapped() = 0;

    virtual GOO_OVERLAPPED* GetListenLapped() = 0;

   

    virtual int OnReadOK(IApplication&, IGooInterface* services, unsigned long trans_len) = 0;

    virtual int OnWriteOK(IApplication&, IGooInterface* services, unsigned long trans_len) = 0;

    virtual bool IsWaitForConnect() const = 0;

    virtual void SetRealConnect() = 0;

    virtual bool IsClientSocket() const = 0;

};

       IGooSysSession 内核层调用,IGooSession用户层调用,如果设计主要是考虑到把某些实现隐藏掉,因为这些功能对用户层来说他不用关心。

 

由于时间问题,先到此,后续。。。。

 

原创粉丝点击