现在的位置: 首页 > 综合 > 正文

编译quickfast解析库(沪深level2行情转码库)

2012年02月03日 ⁄ 综合 ⁄ 共 8023字 ⁄ 字号 评论关闭

编译链接level2行情转码机.

下载quickfast项目(windows平台):

http://quickfast.googlecode.com/files/quickfast_win_src_1_4.zip

下载第三方库:

1,下载activeperl

(google it)

2,下载mpc

http://www.ociweb.com/products/mpc

3,下载boost

(google it)

4,下载xerces

http://xerces.apache.org/xerces-c/

下载 行情转码库的配置脚本setup.bat(gif文件另存为zip,解压可以得到bat文件)

http://hi.csdn.net/attachment/201112/13/0_1323743665laAL.gif

setup.bat配置脚本设置三方库路径和编译器选项

@REM 1) Customize this file by setting variables to suit your environment
@REM 2) Also you should customize QuickFAST.features to enable particular features on your system.
@REM 3) Delete the following line when you finishing customizing this file.
@REM           [==DELETED==]echo See remarks in %0 for information about setting your build environment
@REM 4) And, then run the `m.cmd' to generate *.sln & *.vcproj files
@echo off
REM =====================================================================================
REM EDIT THE FOLLOWING LINES OR SET THESE VALUES IN YOUR ENVIRONMENT BEFORE RUNNING SETUP
if "a" == "a%MPC_ROOT%" set MPC_ROOT=H:\workspace\qf\MPC
if "a" == "a%XERCES_ROOT%" set XERCES_ROOT=H:\workspace\qf\xerces-c-3.1.1-x86-windows-vc-8.0
if "a" == "a%XERCES_LIBNAME%" set XERCES_LIBNAME=xerces-c_3
if "a" == "a%BOOST_VERSION%" set BOOST_VERSION=boost_1_47_0
if "a" == "a%BOOST_ROOT%" set BOOST_ROOT=H:\workspace\qf\%BOOST_VERSION%
REM END OF VALUES TO BE SET
REM =====================================================================================

注意:boost默认编译出来的include和lib不在同一个目录下,需要move一下。

在vc的命令行下,运行这个setup.bat && m.bat就可以生成QuickFast.sln

vs2008打开QuickFast.sln编译连接,生成的文件在Output目录的相应配置文件夹下。

得到库以后,如何使用呢?

这个解决方案提供了很多例子,最简单的是TutorialApplication和InterpretApplication这2个例子。

也可以用doxygen生成文档。

http://hi.csdn.net/attachment/201112/26/0_1324861393eteG.gif

一个简单的例子实现

笔者用Codecs::SynchronousDecoder(同步解码,官方例子使用的是异步解码器)实现了一个简单的解码封装,

通过tcp socket从上游数据源获取fast的码流并且解码,

FAST码流是剥掉了STEP协议头以后STEP协议BODY部分用FAST编码过的内容。

Fast_Steam = Fast(STEP_PACKET - STEP_HEAD) = Fast(STEP_BODY)

FastDecoder.h是导出库的头文件

#ifdef __cplusplus
extern "C"
{
#endif

enum MarketTag
{
    ShenzhenMarket = 0,
    ShanghaiMarket = 1,
};

FASTDECODER_API 
int RunDecoderLoop(const char * pIp
               , unsigned short nPort
               , MarketTag nMarketTag
               , const char * templateFileName
               , const struct IDataExInterface * pNotify
               );

#ifdef __cplusplus
};
#endif

解码以后的数据通过接口中的pNotify接口来通知客户端更新数据

TestFastDecoder.cpp文件

struct IDataExInterface
{
    void (__stdcall * pfnFeedStatus)(ConnectionStatus connStatus);

    // 上海的更新接口
    void (__stdcall * pfnFeed_SHFAST30_UA3202)(const SHFAST30_UA3202_t * );
    void (__stdcall * pfnFeed_SHFAST30_UA3201)(const SHFAST30_UA3201_t * );
    void (__stdcall * pfnFeed_SHFAST30_UA3113)(const SHFAST30_UA3113_t * );

    // 深圳的更新接口
    void (__stdcall * pfnFeed_SZFAST_103)(const SZFAST_103_t *);
    void (__stdcall * pfnFeed_SZFAST_202)(const SZFAST_202_t *);
    void (__stdcall * pfnFeed_SZFAST_201)(const SZFAST_201_t *);
    void (__stdcall * pfnFeed_SZFAST_104)(const SZFAST_104_t *);

};

客户端可以这样调用

void Level2Thread(void * arg)
{
    MarketTag nMarketTag = static_cast<MarketTag>((int)arg);

    IDataExInterface * pNotify = new IDataExInterface;
    memset(pNotify, 0, sizeof(IDataExInterface));
    pNotify->pfnFeedStatus              = FeedStatus;

    switch (nMarketTag)
    {
    case ShenzhenMarket:
        {
            SetThreadAffinityMask(GetCurrentThread(), 1);
            pNotify->pfnFeed_SZFAST_103         = Feed_SZFAST_103;
            pNotify->pfnFeed_SZFAST_104         = Feed_SZFAST_104;
            pNotify->pfnFeed_SZFAST_201         = Feed_SZFAST_201;
            pNotify->pfnFeed_SZFAST_202         = Feed_SZFAST_202;

            RunDecoderLoop(
                "127.0.0.1"
                , 1111
                , MarketTag(ShenzhenMarket)
                , ".\\fasttemplates_2.00.xml"
                , pNotify);
        }
        break;
    case ShanghaiMarket:
        {
            SetThreadAffinityMask(GetCurrentThread(), 2);

            pNotify->pfnFeed_SHFAST30_UA3113    = Feed_SHFAST30_UA3113;
            pNotify->pfnFeed_SHFAST30_UA3201    = Feed_SHFAST30_UA3201;
            pNotify->pfnFeed_SHFAST30_UA3202    = Feed_SHFAST30_UA3202;

            RunDecoderLoop(
                "127.0.0.1"
                , 2222
                , MarketTag(ShanghaiMarket)
                , ".\\template.2.03.xml"
                , pNotify);
        }
        break;
    }
    return ;
}

/**
*
* 简单的开启2个市场的解码线程开始解码
* 导出函数RunDecoderLoop是一个循环过程
* 所以放在2个独立的线程中
*
**/ int main(int argc, char* argv[])
{
    _beginthread(Level2Thread, 0, (void *)ShanghaiMarket);
    _beginthread(Level2Thread, 0, (void *)ShenzhenMarket);

    //Level2Thread((void*)ShenzhenMarket);
    //Level2Thread((void*)ShanghaiMarket);
    
    printf("Press any key to quit decoder.\n");
    getchar();
    return 0;
}

更新一下客户端从配置文件TestFastDecoder.ini读取配置信息

[Shanghai]
IpAddr=127.0.0.1
Port=8888
Template=template.2.03.xml

[Shenzhen]
IpAddr=127.0.0.1
Port=5555
Template=fasttemplates_2.00.xml

新的Level2Thread

void Level2Thread(void * arg)
{
    char szProfile  [MAX_PATH]  = "";
    char szAppName  [MAX_PATH]  = "";
    char szIpAddr   [MAX_PATH]  = "";
    char szTemplate [MAX_PATH]  = "";
    unsigned short wPort = 0;

    MarketTag nMarketTag = static_cast<MarketTag>((int)arg);

    IDataExInterface * pNotify = new IDataExInterface;
    memset(pNotify, 0, sizeof(IDataExInterface));
    pNotify->pfnFeedStatus              = FeedStatus;
    pNotify->pfnFeed_SZFAST_103         = Feed_SZFAST_103;
    pNotify->pfnFeed_SZFAST_104         = Feed_SZFAST_104;
    pNotify->pfnFeed_SZFAST_201         = Feed_SZFAST_201;
    pNotify->pfnFeed_SZFAST_202         = Feed_SZFAST_202;
    pNotify->pfnFeed_SHFAST30_UA3113    = Feed_SHFAST30_UA3113;
    pNotify->pfnFeed_SHFAST30_UA3201    = Feed_SHFAST30_UA3201;
    pNotify->pfnFeed_SHFAST30_UA3202    = Feed_SHFAST30_UA3202;

    SetThreadAffinityMask(GetCurrentThread()
                         , (nMarketTag == ShenzhenMarket) ? 0 : 1);

    GetModuleFileNameA(GetModuleHandleA(NULL), szProfile, _countof(szProfile)-sizeof(szProfile[0]));
    strrchr(szProfile, '\\')[1] = 0;
    strcat_s(szProfile, _countof(szProfile), "TestFastDecoder.ini");

    strcpy_s(szAppName
        , _countof(szAppName) - sizeof(szAppName[0])
        , (nMarketTag == ShenzhenMarket) ? "Shenzhen" : "Shanghai");

    GetPrivateProfileStringA(szAppName
        , "IpAddr"
        , NULL
        , szIpAddr
        , _countof(szIpAddr)-sizeof(szIpAddr[0])
        , szProfile);

    wPort = GetPrivateProfileIntA(szAppName
        , "Port"
        , 0
        , szProfile);

    GetPrivateProfileStringA(szAppName
        , "Template"
        , NULL
        , szTemplate
        , _countof(szTemplate)-sizeof(szTemplate[0])
        , szProfile);

    RunDecoderLoop(
            szIpAddr
            , wPort
            , nMarketTag
            , szTemplate
            // , nMarketTag == ShenzhenMarket 
            // ? ".\\fasttemplates_2.00.xml"
            // : ".\\template.2.03.xml"
            , pNotify);

    //std::cout<<szIpAddr<<wPort<<szTemplate<<nMarketTag<<std::endl;

    return ;
}

用Codecs::SynchronousDecoder解码fast的几个重要步骤

1, 构造xml解析对象

/************************************************************************
*
* 全局的xml解析类
* 
* 注意: 多线程同时构造parser会资源冲突
*       
*
************************************************************************/
static Codecs::XMLTemplateParser parser;

2, 解析xml模板生成fast模板
 

/////////////////////////////////////////////
// Parse the templates from the template file
// errors are reported by throwing exceptions
// which are caught below.
std::ifstream tmplFile(templateFileName, openMode);
Codecs::TemplateRegistryPtr registry;
try {
   registry = parser.parse(tmplFile);
}catch (std::exception & e){
   std::cerr << e.what() << std::endl;
   return -1;
}

3, 创建一个decoder对象
 

//////////////////////////////////////
// Create a sync decoder and
// setup attributes.
Codecs::SynchronousDecoder * pDecoder 
    = new Codecs::SynchronousDecoder(registry);
pDecoder->setHeaderBytes(0);
pDecoder->setResetOnMessage(false);
pDecoder->setLimit(0);

4, 实现一个消息消费者,并且注册给解码器

//////////////////////////////////////
// Create an application object to use
// the incoming data.  In this case to
// accept complete messages and interpret
// them to standard out.
CMessageConsumerImpl * pHandler 
    = new CMessageConsumerImpl(nMarketTag
                               , pNotify
                               , pDecoder);
//////////////////////////////////////
// and use the interpreter as the consumer
// of generic messages.
Codecs::GenericMessageBuilder builder(*pHandler);

5, 接收网络数据包(放置在pFastBody, 长度位nBodyLength),开始解码

pDataSource = new Codecs::DataSourceBuffer(pFastBody , pFastHeader->nBodyLength);

try{
  pDecoder->reset();
  pDecoder->decode(*pDataSource, builder);
} catch (std::exception & e)
{
  std::cout<<e.what()<<std::endl;
}
delete pDataSource;
pDataSource = NULL;

6,实现消息消费者接口

/// @brief A message consumer that attempts to produce a human readable version
/// of a message that has been decoded by QuickFAST.
class CMessageConsumerImpl : public Codecs::MessageConsumer

重写消费消息函数

virtual bool consumeMessage(Messages::Message & message);

7,消费消息的过程就是消息的格式化过程

 在消息的格式化过程中,主要是遍历Message的各个filed,如果field

一般类型,直接转换成相应的值;如果是sequencegroup,则需要将

field转换成sequencegroup,遍历;另外,由于sequence里面的每一个

item也是一个Message结构,所以需要以Message的方式遍历结构的每一个成员;

foreach(item in seq)  
    foreach(member in item)

========================

8, 待续

fast手工解码,参考spec

========================

输出:

=================================================================

项目源文件下载(将下面的gif链接另存为zip,解压->重命名->解压,有加密,确实有需要的朋友请留言获取)

最新版本

version 2.0,修改了日志打印方式和配置文件加载quickfast-v2-[8n0].zip.png

http://hi.csdn.net/attachment/201112/27/0_132498087296Py.gif

历史版本

version 1.0,项目源文件Examples-8n0.zip

http://hi.csdn.net/attachment/201112/26/0_132486187064m4.gif

抱歉!评论已关闭.