Skip to content

QuantBox XAPI备忘录

William Fouvy edited this page Apr 26, 2015 · 9 revisions

设计理念Zen Of XAPIs

列队

抽象上,所有的XAPIs项目的设计都遵循:指令入队消息列队,回调指令消息列队,而且二者设计上是对称的(处女座style)。 列队的设计是采用多生产者,单消费者的无锁消息列队,消息头文件是MsgQueue.h。无锁列队在本项目历史上采用了多个版本(至少4个)。最后,伟大的FV建议采用ArrayLockFreeQueue.h这个无锁列队。因为,它简单并且容易调试错误。

线程

所有的XAPIs函数(API函数和SPI回调函数),都在MsgQueue.h内部的一个线程中执行。

接口的出入口

静态函数XRequest,是各个柜台接口对象的入队消息函数接口,详见ApiHeader.h头文件. 各个XAPI都需要注册一个XResponse的静态回调函数. 两个出入口的参数一致,是对称的(处女座style again). 虽然一行代码和公式,都会导致读者减半,但伟大的FV还是不得不列出下面一行函数类型声明,就是上面提到的XRequest和XResponse函数的类型是:

typedef void* (__stdcall *fnOnRespone) (char type, void* pApi1, void* pApi2, double double1, double double2, void* ptr1,int size1, void* ptr2,int size2, void* ptr3,int size3);

第一个输入参数代表出入指令类型,后面的两个pApi一般没固定类型,主要用于装对象或者消息列队对象.两组double参数主要是用来装返回值.三组ptr,size主要用于装回调消息内容的,ptr放指针,size放该数据的大小校验.

XAPIs的C封装

XAPIs系列项目支持多个不同的股票期货柜台项目,为了方便做到能够对已经编译好的柜台接口进行调用,XAPIs在设计其统一的C封装接口(代码参见子项目QuantBox_XAPI)的时候,调用必须依赖于下列执行6步骤,详细细节参看XApiC.h头文件:

  1. X_LoadLib 第一个输入参数XAPIs柜台接口库文件绝对地址或者相对文件地址,返回这个库的内存指针plib地址
  2. X_GetFunction 第一个参数输入1.中的返回值pLib指针,第二个参数是"接口出入口"中提到的指令入口"XRequest"函数名(如果没输入第二个变量就是默认这个字符串函数名,详见XApiC.h头文件),用于取得XAPIs柜台封装接口的函数指针返回值pFun
  3. X_Create 第一个参数输入2.中的pFun指针,创建柜台接口对象,返回对象指针pApi(自己转一下类型)
  4. X_Register 第一个参数输入2.中的pFun指针,第二个参数输入3.中的pApi对象,第三个参数带入fnOnRespone类型的静态函数指针,第四个参数属于情怀参数,对称性设计(处女座 style triple kill)一般是带入外部对这个pApi对象进行二次封装的对象.
  5. X_*** 系列其它的C接口,第一个参数输入参数都是2.中的pFun,第二个参数都是3.中生成的pApi对象,其它参数就是细化了相应的柜台指令接口参数类型
  6. X_FreeLib 你懂得

XAPIs的C++封装

在上面XAPIs的C封装的基础上,重新组织了指令接口形成了C++的封装.主要的信息在QuantBox_XAPI的XApiCpp.h头文件中.我们要在自己的C++项目中使用所有XAPIs柜台封装接口,直接从这个头文件开始.具体的Demo详见子项目QuantBox_XAPI_TEST中的QuantBox_XAPI_TEST.cpp实现文件.这个比较简单.

虽然比较简单,伟大的FV还是啰嗦一下,具体还是看Demo比较清楚.

  1. 整个封装参考期货行业接口标准CTP的设计.我们包含进来XApiCpp.h头文件,
  2. 然后继承CXSpi类,实现自己想要对回调数据的处理逻辑类CXSpiImpl.
  3. 然后创建CXApi这个类的对象pCXApi,通过这个方法CXApi::CreateApi,第一个参数带入需要初始化接口的库文件地址,
  4. 然后初始化pCXApi->Init();初始化的时候CXApi开始load动态库进来,
  5. 然后把类CXSpiImpl对象pCXSpiImpl注册到CXApi对象上,即pCXApi->RegisterSpi(pCXSpiImpl);
  6. 然后,pCXApi->Connect连接柜台,这个时候CXApi才进行柜台接口对象的创建,并注册类的静态方法回调函数过去;这个静态方法,对返回的对象和消息指令类型进行分发.

XAPIs的C#封装

C#封装项目在本项目的历史上是早于C/C++的封装的,C#的封装在子项目QuantBox.XAPI中.因此C#的封装并没有基于前面的两个,而是独立的,但封装的思想是相似的.C#的封装采用的是P/Invoke加Marshal的模式进行的,这种方法直接加载各个柜台XAPIs接口封装的动态库.这种模式是不如C++/CLI的封装运行速度快.

XAPIs的所有的封装方式都依赖于XAPIs上述提到的设计理念的.都要牢牢把握一个中心两个基本点,一个中心是统一的动态加载库,两个基本点是,入口函数XRequest和出口回调函数XResponse。C#的封装同样遵循一个中心两个基本点,一个中心见InvokeBase.cs以及它的windows和linux的动态库加载派生类DllInvoke.cs和SoInvoke.cs。这三个文件做的事儿就是要实现这一个中心和两个基本点,就是加载动态库进来和取到函数指针地址。真正统一这个理念的工作是在Proxy.cs里面实现的,它负责调用上面的Invoke系列方法,以及取得XRequest函数指针地址。回调函数接口的XResponse的注册,是在BaseApi.cs中的Connect方法中实现的。BaseApi.cs的派生类XApi.cs以及其它的几个同样开头的cs文件中,实现回调函数分发以及回调函数数据从unmanaged数据用Marshal方式转换成managed的数据.XApi.cs中的回调函数使用的是函数指针的方法.如果要使用事件触发的方式回调的话,请使用XApiWrapper.cs这个类.他在XApi.cs的基础上做了处理.

那么如何使用C#版的封装呢,看下QuantBox.XAPI项目中的program.cs里面有详细的Demo.这个比较简单.