前营中间件(5) - 异步发包和客户端的操作函数

来源:互联网 发布:淘宝小号一个月刷70单 编辑:程序博客网 时间:2024/05/07 12:56

上次,我们介绍了同步发送接收模式,现在我们介绍一下异步模式,下面是异步发送函数:

/**

     * 函数名称:异步发送消息

     * 函数功能:将数据发送出去,系统会自动打个发送标志,并把对应的序号写入消息中并返回,应答

     *         序号写为。

     * 参数列表:

     *         @uiSessionID      : 会话ID

     *         @uiFuncNo         : 功能号

     *         @usSendBuffHandle : 发送的数据包

     *         @usSeqNo          : 数据包的序号

     *         @return              : Z_OK——成功,< 0 ——失败

     * 修改记录:20090908 赵海杰

     */

   virtual int   SendPack(unsigned int uiSessionID, unsigned int uiFuncNo, unsigned short usSendBuffHandle, unsigned short &usSeqNo) = 0;

它和同步发送相比,少了两个参数接收缓冲区和等待时间,多出另一个参数usSeqNo, usSeqNo为消息序号,由系统维护,可以用此值来匹配异步请求的应答包(不过一般情况下不会用到),别的参数没有什么特别,就不介绍了.

我们进行发送后,还需要接收,我们通过回调函数进行接收操作,下面是回调函数的定义:
/**

 * 函数名称:接收应答回调函数

 * 函数功能:用来处理就应答和主推两种方法发送过来的消息

 * 参数列表:

 *         @lpParam      :   客户传入的参数

 *         @uiSessionID  :   接收到请求的会话号

 *         @usRecvBuffHandle:   接收数据缓冲区

 *         @usSequenceNo :   会话消息序号

 *         @lpPointer    :   附加信息

 *         @Result           :   处理结果,如果返回Z_OK说明被处理过了,不需要调用下一个回调函数进行处理,如果返回

 *                          Z_OK,系统会调用下一个回调函数进行处理,如果会话层的回调函数链被调用完了,则调用全局的回调函数链处理。

 * 修改记录:

 *            20090329   赵海杰     创建

 **/

typedef int   (__stdcall *LPONRECVFUNC)(void* lpParam, unsigned int uiSessionID, unsigned short usRecvBuffHandle, unsigned short usSequenceNo, void* lpPointer);

第一个参数,为我们在添加回调函数时设置的值,第二个参数为会话号,第三个是接收数据所在的缓存区,第四个为消息序号,和发送时的序号是一样的,第四个值是一个标志位,此值指向一个字符,这个字符表示数据处理时发生的状态.这个值的定义在ZCommError.h,如下:

enum ErrorNoList

{

    // 通讯解包错误号,CHAR型会记录在返回包中

    EP_NORMAL = 0,              // 正确消息包

    EP_SYSTEM_ERROR,         // 系统处理错误

    EP_UNPACK_FAILED,        // 解包错误

    EP_CLOSE_SESSION,        // 关闭会话的消息

    EP_CREATE_SESSION,          // 创建会话的消息

    EP_EXCEED_ROUTER,        // 路由超限,中间经过的中间件太多

EP_NO_ROUTER,           // 没有合知的路由

…..

}

我们在处理回调函数中,要对这个值进行判断,回调函数返回Z_OK,表示处理成功.

我们定义好回调函数后,就需要把回调函数设置到系统中,我们提供两个函数,一个函数,把回调函数添加到全局中,可以处理所有的异步消息;一个函数,把回调函数添加到会话中,只能处理会话的异步消息.当然,我们的异步消息会先调用会话的回调函数,如果会话的回调函数,没有处理此异步消息的功能(即返回非Z_OK),才会调用全局的回调函数,下面两个声明,第一个是添加全局的回调函数,第二个是添加会话的回调函数,两个函数最后一个参数,是客户传入的参数,会原样不动的传给回调函数的第一个参数.

/**

     * 函数名称:添加一个全局的应答处理回调函数

     * 函数功能:将此回调函数添加到应答处理回调函数链的头部

     * 参数列表:

     *         @lpOnRecvFunc : 回调函数指针

     *         @lpParam      :   传入的参数

     *         @return    : Z_OK——成功,< 0 ——失败

     * 修改记录:20090908 赵海杰

     */

virtual int   AddOnRecvFunc(LPONRECVFUNC lpOnRecvFunc, void* lpParam) = 0;

/**

     * 函数名称:添加一个会话的应答处理回调函数

     * 函数功能:将此回调函数添加到应答处理回调函数链的头部

     * 参数列表:

     *         @uiSessionID  : 会话ID

     *         @lpOnRecvFunc : 回调函数指针

     *         @lpParam      :   传入的参数

     *         @return    : Z_OK——成功,< 0 ——失败

     * 修改记录:20090908 赵海杰

     */

   virtual int   AddOnRecvFunc(unsigned int uiSessionID, LPONRECVFUNC lpOnRecvFunc, void* lpParam) = 0;

无论对会话还是全局都可以添加多个回调函数,在调用时,会先调用后添加的,当回调函数返回非Z_OK,才会调用先前添加的. RemoveOnRecvFunc是删除回调函数的功能,它也提供两个函数,分别删除全局或会话私有的回调函数.

下面是异步回调函数的例子,ClientTest中可以取到相应的代码.

int             __stdcall OnRecv(void* lpParam, unsigned int uiSessionID, unsigned short usRecvBuffHandle, unsigned short usSequenceNo, void* lpPointer)

{

    char cFlag = *(char*)lpPointer;

    char szBuff[1024];

    unsigned char ucRouterFlag(0);

    unsigned int uiFuncNo;

    unsigned long iBuffLen(1024);

    CTime t(time(NULL));

    CString str;

    if(EP_CREATE_SESSION == cFlag)

    {

                  str.Format("功能号:000]  新会话建立,会话号:%d/r/n", uiSessionID);

                  str = t.Format("[%H-%M-%S-接收-") + str;

    }

    else if(EP_CLOSE_SESSION == cFlag)

    {

                  str.Format("功能号:000]  会话关闭,会话号:%d/r/n", uiSessionID);

                  str = t.Format("[%H-%M-%S-接收-") + str;

    }

    else if(EP_NO_ROUTER == cFlag)

    {

                  lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                  str.Format("功能号:%d]  没有路由可以转发,会话号:%d/r/n", uiFuncNo, uiSessionID);

                  str = t.Format("[%H-%M-%S-接收-") + str;

    }

    else if (EP_NORMAL == cFlag)

    {

                  int iRet(0);

                  lpClientAPI->GetRouterFlag(usRecvBuffHandle, ucRouterFlag);

                  if (0 == ucRouterFlag)

                  {

                                int iRet = lpClientAPI->DetachBuffer(usRecvBuffHandle, szBuff, iBuffLen);

                                szBuff[iBuffLen] = 0;

                                lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                if(0 == iRet)

                                {

                                              str.Format("功能号:%d]  %s/r/n", uiFuncNo, szBuff);   

                                              str = t.Format("[%H-%M-%S-接收-") + str;

                                }

                  }

                  else if(BROADCAST_ROUTER_INFO == ucRouterFlag)

                  {

                                iRet = lpClientAPI->DetachBuffer(usRecvBuffHandle, szBuff, iBuffLen);

                                if(0 == iRet)

                                {

                                              szBuff[iBuffLen] = 0;

                                              lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                              str.Format("功能号:%d]  %s/r/n", uiFuncNo, szBuff);

                                              str = t.Format("[%H-%M-%S-广播-") + str;

                                }

                  }

                  else if(MULTICAST_ROUTER_INFO == ucRouterFlag)

                  {

                                iRet = lpClientAPI->DetachBuffer(usRecvBuffHandle, szBuff, iBuffLen);

                                if(0 == iRet)

                                {

                                              szBuff[iBuffLen] = 0;

                                              lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                              str.Format("功能号:%d]  %s/r/n", uiFuncNo, szBuff);

                                              str = t.Format("[%H-%M-%S-多播-") + str;

                                }

                  }

                  else if(MULTICAST_ROUTER_REMOVE == ucRouterFlag)

                  {

                                lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                str.Format("功能号:%d]  删除多播/r/n", uiFuncNo);

                                str = t.Format("[%H-%M-%S-多播-") + str;

                  }

                  else if(MULTICAST_ROUTER_ADD ==ucRouterFlag)

                  {

                                lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                str.Format("功能号:%d]  添加多播/r/n", uiFuncNo);

                                str = t.Format("[%H-%M-%S-多播-") + str;

                  }

                  else if(BROADCAST_ROUTER_RESET ==ucRouterFlag)

                  {

                                lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                str.Format("功能号:%d]  广播重置/r/n", uiFuncNo);

                                str = t.Format("[%H-%M-%S-广播-") + str;

                  }

                 

                  else

                  {

                                int iRet = lpClientAPI->DetachBuffer(usRecvBuffHandle, szBuff, iBuffLen);

                                if(0 == iRet)

                                {

                                              szBuff[iBuffLen] = 0;

                                              lpClientAPI->GetFuncNo(usRecvBuffHandle, uiFuncNo);

                                              str.Format("功能号:%d]  %s/r/n", uiFuncNo, szBuff);

                                              str = t.Format("[%H-%M-%S-未知-") + str;

                                }

                  }

    }

    else

    {

                  str.Format("  错误,错误标识:%d/r/n", cFlag);

                  str = t.Format("[%H-%M-%S-接收]") + str;

    }

    return 0;

}

在上面的代码中,有两个函数是我们没用的, GetFuncNo是取功能号的,功能号保存在缓存区中, GetRouterFlag是取消息包路由方式,可以由这个值得到,此消息是普通消息包,还是多播包或广播包.对于多播和广播的相关信息,我们以后再谈,此先了解.

 

现在我们把的LPCLIENTAPI函数基本上都认识了,还剩下以下几个:

GetVersion取得接口的版本号,客户使用时,先调用此函数取得版本号和接口文件上的版本号API_VERSION相比较,如果版本不匹配,需要进行出错处理,这个函数是为了防止DLL HELL的问题.

CloseMultiCast关闭多播,我们订阅多播后,可以在客户端进行关闭,因为多播也是以功能号为基础的,所以此函数需要提供会话号和功能号.关于多播的相关知道,我们其后再讲.

GetDataSize获得缓存区数据的大小.

GetConnectStatus获取连接状态.

最后三个函数都是与数据包打包器相关的,我们以后再介绍.

好了,现在客户端所提供的所有功能,我们都了解了.我们下次将会讲一下组件开发包的接口.

原创粉丝点击