转载https://www.cnblogs.com/anyun/p/9268895.html

目前上期技术CTP系统提供的API版本是C++版本

SWIG是一个能将C/C++接口转换为其他语言的工具,目前可以支持Python,Java,R等语言。

本文主要介绍Windows 32/64位平台下利用Swig工具将CTP C++接口API转换为Java可调用的接口。

1、从CTP官网下载最新API包,包中包含32位和64位。API文件包清单:

2、下载安装Swig软件:

3、编写接口*.i文件。swig是根据h头文件编写接口的,需要输入的h文件编写在i文件中。

这里着重说一下转换中遇到的问题。首先swig中转换 char *str[] 和char **时会转换成SWIGTYPE_p_p_char类型,这里需要various.i文件。various.i文件是swig自带的,将swig/Lib/java/various.i拷贝过来即可。在API文件包中创建thostapi.i 和various.i文件,thostapi.i是一个接口文件,用于告诉swig为哪些类和方法创建接口。various.i是用于将C++接口中的数组参数转换为java 的Array的工具类。

1 %module(directors="1") thosttraderapi2 %include "various.i"

3 %apply char **STRING_ARRAY { char *ppInstrumentID[] }4 %{5 #include "ThostFtdcMdApi.h"

6 #include "ThostFtdcTraderApi.h"

8 %}

26 %feature("director") CThostFtdcMdSpi;27 %ignore THOST_FTDC_VTC_BankBankToFuture;28 %ignore THOST_FTDC_VTC_BankFutureToBank;29 %ignore THOST_FTDC_VTC_FutureBankToFuture;30 %ignore THOST_FTDC_VTC_FutureFutureToBank;31 %ignore THOST_FTDC_FTC_BankLaunchBankToBroker;32 %ignore THOST_FTDC_FTC_BrokerLaunchBankToBroker;33 %ignore THOST_FTDC_FTC_BankLaunchBrokerToBank;34 %ignore THOST_FTDC_FTC_BrokerLaunchBrokerToBank;35 %include "ThostFtdcUserApiDataType.h"

36 %include "ThostFtdcUserApiStruct.h"

37 %include "ThostFtdcMdApi.h"

38 %feature("director") CThostFtdcTraderSpi;39 %include "ThostFtdcTraderApi.h"

忽略8个方法,因为涉及到将字符串转换为char类型,有问题。后面可以省略注释掉这几个方法。

4、生成java接口:

在当前文件夹创建src/ctp文件夹用于放置生成的java文件

..\..\swigwin-2.0.11\swig.exe -c++ -java -package ctp.thosttraderapi -outdir src -o thosttraderapi_wrap.cpp thostapi.i

运行完成之后,可在当前文件夹中看到用于包装原来C++接口的文件:

5、通过C++得到java可调用的动态库

创建一个C++工程,应用程序类型选择DLL,将以下文件添加到工程中去:

将dk目录\Java\jdk1.8.0_111\include下的jni.h和win32文件夹下的jni_md.h, jawt_md.h一共三个文件

拷贝到安装vs的include目录底下\Microsoft Visual Studio 12.0\VC\include。

因为thosttraderapi_wrap.cpp文件中包含了,是用于生成Java可调用接口的库文件。

在thosttraderapi_wrap.cpp中将如下8个函数注释掉,这几个函数中涉及到将字符串转换为char类型,有问题。当你编译时报错说字符常量字数太多,可以看到‘xxxx’的字符常量。这是ctp自带的错,但是没有应用所以没有被他们发现。把这些函数注释即可。

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1VTC_1BankBankToFuture_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1VTC_1BankFutureToBank_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1VTC_1FutureBankToFuture_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1VTC_1FutureFutureToBank_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1FTC_1BankLaunchBankToBroker_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1FTC_1BrokerLaunchBankToBroker_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1FTC_1BankLaunchBrokerToBank_1get

Java_ctp_thosttraderapi_thosttradeapiJNI_THOST_1FTDC_1FTC_1BrokerLaunchBrokerToBank_1get

之后进行编译,生成java可调用的动态库文件thosttraderapi_wrap.dll:

6、创建java项目,将三个动态库和之前生成的src/ctp包拷贝到项目,并加载动态库进来:

到此java API制作完成,可以进行java开发了。

一、普通回报中文乱码

此类型常见的乱码主要存在于 CThostFtdcRspInfoField 结构体中的 ErrorMsg 字段,用于在接口调用存在错误时返回必要参考信息,除此之外,通过结构体 CThostFtdcInstrumentField 获取合约中文名称等信息出现乱码也是常见的乱码问题之一。

具体原因:

1. Java基于Unicode字符集,并有多个类库实现了Unicode标准,运行时内部字符串使用UTF-16,默认使用UTF-8序列化字符串。因此当JNI返回字符串时,应调用NewStringUTF方法(当输入为UTF-8时),或者调用NewString(当输入为UTF-16时)方法,最终生成可以在Java中返回的jstring。

2. CTP官方使用的是国标编码,也就是(GB18030>GBK>GB2312)中的一种。

3. SWIG封装时对JNI返回的字符串默认调用JNI中的NewStringUTF方法,显然,CTP官方使用的并不是UTF-8编码,因此出现了乱码,且这个过程中会产生信息丢失,是一个不可逆的错误。

存在如下两类解决方案:

第一类为定义宏 NewStringByGB2312 如下,然后搜索所有的C++文件中的 if (result) jresult = jenv->NewStringUTF((const char *)result); 用该宏替换。

define NewStringByGB2312\

if(result)\

{\

jclass str_cls = jenv->FindClass("java/lang/String");\

jmethodID constructor_mid = jenv-> GetMethodID(str_cls,"","([BLjava/lang/String;)V");\

jbyteArray bytes = jenv->NewByteArray( strlen(result));\

jenv->SetByteArrayRegion(bytes, 0, strlen(result),(const jbyte*) result);\

jstring charsetName = jenv->NewStringUTF("gb2312");\

jresult = (jstring)jenv->NewObject(str_cls, constructor_mid, bytes, charsetName);\

jenv->DeleteLocalRef(str);\

jenv->DeleteLocalRef(bytes);\

jenv->DeleteLocalRef(str_cls);\

}\

这样操作通过C++直接调用Java中的String构造方法,传入C++中的字节数组,设置字符集,因此能够正确解析编码,转换为正确的Java字符串对象。

第二类为借助第三方库iconv。在SWIG配置文件中加入如下代码, 并在生成的代码中加入头文件iconv.h和相关运行库。

%include "various.i"

%typemap(out) char[ANY], char[] {

if ($1) {

iconv_t cd = iconv_open("utf-8", "gbk");

if (cd != reinterpret_cast(-1)) {

char buf[4096] = {};

char **in = &$1;

char *out = buf;

size_t inlen = strlen($1), outlen = 4096;

if (iconv(cd, in, &inlen, &out, &outlen) != static_cast(-1))

$result = JCALL1(NewStringUTF, jenv, (const char *)buf);

iconv_close(cd);

}

}

}

这样操作生成的代码会借助iconv库在C++层面将GBK编码转换为UTF-8编码,因此JNI生成字符串对象时可以生成正确的Java字符串对象。

二、结算单乱码

查询结算单返回结果回调中字段Content是一个长度为501的数组。显然我们的结算单长度往往不止501,所以我们需要注意这个回调方法中还有bIsLast标志,因为结算单实际是多次回报分段传输的,且第501个字符为'\0',仅用于占位,这并不代表字符串结束。

在更底层的字符编码存储传输层面,我们上文提到的国标编码(GB18030>GBK>GB2312)是变长的,因此不能确保每个批次的第500位结束的时候刚好是一个字符结束,因此有可能存在一个字符所属存储编码的前n个字节存在于当前回报的数组尾部,后n个字节存在于下一次回报数组头部。如果我们不做任何修改,SWIG生成的C++和Java代码会将每次回报都直接生成一个字符串从C++返回到Java层面,因此我们会看到结算单一部分正确,一部分错误,混杂部分乱码,或者有时候完整,有时候不完整。

针对上述情况,我们的解决思路是对服务器返回的n个501长度的数组截取每个数组的前500位进行拼接,直到收到bIsLast标记,组成一个n*500的数组。这个操作可以在C++中完成,也可以在Java中完成,显然,在C++中完成会做较大的修改,因此我们可以选择在Java中修改。具体步骤如下。

在cpp中搜索CThostFtdcSettlementInfoField_1Content_1get函数,将函数返回类型改为jbyteArray,将内容改为如下:

jbyteArray jresult = 0 ;

CThostFtdcSettlementInfoField *arg1 = (CThostFtdcSettlementInfoField *) 0 ;

char *result = 0 ;

(void)jenv;

(void)jcls;

(void)jarg1_;

arg1 = *(CThostFtdcSettlementInfoField **)&jarg1;

result = (char *) ((arg1)->Content);

return result;

请注意仅需修改返回类型和内容代码,方法名称是swig生成的,不能修改。

完成上述步骤后,手动将 CThostFtdcSettlementInfoField.java 文件中的函数  getContent() 方法的返回类型改为byte[],将其调用的其他类的方法的返回类型也改为byte[]直到无错为止。

在Java中完成拼接后,使用 new String(contentBytes,"GBK"),便可得到完全正确的结算。需要提示的是,最后一组从C++返回到Java的Byte[]长度不一定是501,请根据实际长度处理。

————————————————

版权声明:本文为CSDN博主「景色正好」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/pjjing/article/details/103104047

java ctp行情_CTP转JAVA接口相关推荐

  1. java ctp行情_javaCtp: java版本期货程序化交易系统,包括行情服务,交易服务会逐步完善...

    java_vnpy 介绍 java版本期货程序化交易系统,包括行情服务,交易服务会逐步完善,CTP版本上期技术官网下载6.3.15 穿透式, 目前项目无架构设计,只针对ctp进行封装调用,实现基本交易 ...

  2. java ctp行情_java-ctp

    java-ctp java包装的上期ctp,用swig技术实现. 2014-4-7 10:09:11 项目已经搭建好,上传到这里方法还不会.时间比较紧,有空上传上来. 2014-7-31 22:43: ...

  3. java ctp行情demo_CTP-Api行情Demo版源码

    代码片段和文件信息 #include "MdSpi.h" #include using namespace std; #pragma warning(disable : 4996) ...

  4. c# typescript_在任何IDE中从C#,Java或Python代码获取TypeScript接口的简单方法

    c# typescript by Leonardo Carreiro 莱昂纳多·卡雷罗(Leonardo Carreiro) 在任何IDE中从C#,Java或Python代码获取TypeScript接 ...

  5. Java进阶篇(一)——接口、继承与多态

    前几篇是Java的入门篇,主要是了解一下Java语言的相关知识,从本篇开始是Java的进阶篇,这部分内容可以帮助大家用Java开发一些小型应用程序,或者一些小游戏等等. 本篇的主题是接口.继承与多态, ...

  6. java datetime和date_Java 8时间接口localDateTime和Date的对比

    java8提供了新的时间接口.相对Date,Calendar,个人感觉最大的好处是对时间操作的学习成本很低,比Calendar低. 1. LocalDate,LocalTime,LocalDateTi ...

  7. JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]

    类的继承 Java只支持单继承,不允许多重继承 - 一个子类只能有一个父类 - 一个父类可以派生出多个子类 这里写图片描述 子类继承了父类,就继承了父类的方法和属性. 在子类中,可以使用父类中定义的方 ...

  8. java之集合框架一Collection接口

    1.集合的由来: 我们学习的是面向对象的语言.而面向对象语言对事物的描述是通过对象体现的.为了方便对多个对象进行操作,我们就必须把多个对象进行存储.而要想存储多个对象,就不能是一个基本的变量,而应该是 ...

  9. JDK中提供的实现——通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例

    JDK中提供的实现 在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例. 1 ...

最新文章

  1. js调用python脚本_javascript – 如何从NodeJs调用python脚本
  2. 【Luogu】P3224永无乡(splay)
  3. 【风控场景】互利网上数字金融典型场景: 网络营销
  4. python 多分类 recall_python实现二分类和多分类的ROC曲线教程
  5. 4 关卡流 进阶_儿童桌游要不要鸡血的过关?关卡制儿童桌游介绍与方法论
  6. mysql 5.7.23要钱吗_最新mysql 5.7.23安装配置图文教程
  7. VSCode 用户自定义片段 snippet 基本语法说明
  8. dg oracle 切换模式_谈谈dg切换涉及的概念:switchover和failover区别
  9. 如何区分电梯卡为id卡ic卡_电梯刷卡系统基本属性
  10. 修改msde登录方式,设置sa密码为空
  11. vss(2005)使用详解
  12. 微信小程序获取用户信息(附代码、流程图)
  13. OpenGL如何显示透明PNG
  14. response下载文件
  15. Arduino基础入门篇01—进入Arduino的世界
  16. Pandas是什么?Pandas库下载和安装!
  17. useNavigate使用报错
  18. hibernate基础(十四):二级缓存
  19. python matplotlib 绘制K线图(蜡烛图)
  20. NLP-中文、英文分词

热门文章

  1. LED的C语言应用程序
  2. gerrit refs相关的一些小研究
  3. python模块--datetime时间加减、时间转时间戳、GMT时间格式转换
  4. 我的Android进阶之旅------Android使用AlarmManager全局定时器实现定时更换壁纸
  5. react调用摄像头拍照
  6. C语言 缓存区溢出 3221225725
  7. 人员与叉车防撞预警方案
  8. 称重传感器的防护等级
  9. 分分钟让你学会栈和队列
  10. 51安居安防手电筒拆解