`
yangyi
  • 浏览: 114531 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

浅谈Java中的通信机制及与C/C++ API的集成

    博客分类:
  • Java
阅读更多
背景:
对于旧有系统的改造和升级,最苦恼的莫过于跨平台,跨语言。我的一个朋友最近从Java专向了专攻.NET——因为.NET的CLR既有类似Java虚拟机概念这种已经被证明很成功的底层托管能力。又对于Windows的就有桌面应用提供了良好的兼容。
最近我的一个个人项目也面临着这样的需求。一个C语言开发的中间件,通过API暴露给二次开发及插件应用。现在由于对其应用的需求变得日趋复杂,而且正在脱离Unix的管理环境,走向基于JWS这样的BCS管理。有朋友推荐我用JNI,但这样一是增加了耦合度,二是让Java睡在JNI感觉不太安稳。在认知了上下两层的系统平台后,问题变得明朗起来:如何在HTTP协议下实现Java和C之间的交互?
思路:
本人对Java比较熟悉,先从Java的角度入手,Java间的通信方法:
1 通过URL,Applet/JWS访问被影射到URL的动态资源(Servlet)
2 通过URL,Applet/JWS访问共享的静态资源(Server定期更新静态资源)
3 通过序列化和反序列化,实现简单对象的传输(比如Resin的Hessian框架就提供了这种通信的方式)
4 通过一些工具做代码生成,利用Web Services实现客户端和服务端的交互
此外脱离HTTP,还可以做RMI,socket编程

现在问题是通信的一端由Java变成了C/C++, 于是, 解决方案1需要把动态资源由CGI来定义,而方案3变得不再适用。于是方案有:
1 通过URL,Applet/JWS访问被影射到URL的动态资源(CGI)
2 通过URL,Applet/JWS访问共享的静态资源(Server定期更新静态资源)
3 通过一些工具做代码生成,利用Web Services实现客户端和服务端的交互(×××这是我们讨论的重点×××)

解决方案:
现在针对上文提出的3中通信方式中的1和3谈一谈实现的方法,2的实现方案比较灵活,需要发挥大家的想象力了:)
针对CGI:
首先CGI可以配置在各种主流的服务器中作为后端的脚本运行。大家可能对Servlet更熟悉一些。
CGI可以用脚本写,也可以用C来实现。CGI被触发后,通过系统的环境变量来获得输入,在处理完毕后向标准输出中输出结果。
由此可以想见,Web服务器在接受到来自HTTP协议的请求后,首先把请求的参数获取到,然后设置到环境变量里。
根据对访问的URL的解析和服务器自身的配置,找到服务于请求的CGI程序的位置,然后执行这个程序。
这个程序被执行后通过环境变量得到了服务器先前设置在环境变量中的参数。在经过一些复杂的逻辑操作后,向标准输出输出结果。
这个输出又被Web服务器所捕获,转而传递回请求的客户端。
更多关于CGI的知识和理解,大家可以通过google来寻找答案

上述CGI的方式可以让我们直接获取到结果,但是方案比较原始和基础。其缺点有:
1 需要自己制定类型传输协议,做封装和拆封,否则只支持字符串
2 我们不会为了要用C的API就给它装一个或者自己实现一个Web服务器的,这让我们的底层程序显得蠢笨而冗余。我们希望能有一个超薄的Server外壳,
在对API封装后,通过某个端口进行开放即可。

针对Web Servcies:
Based on上面的两个不足,我们只能把希望寄托在Web Services身上了,
笔者在这里推荐给大家的是在C/C++很著名的Web Services工具gSOAP。大家可以到http://gsoap2.sourceforge.net/上去下载这个工具。
通过这个工具,我们可以做到:
1 一个Stand-alone的服务器外壳
2 一个根据API程序自动生成的Web Services服务
3 一个WSDL描述符文件

下面说明有关基于gSOAP的Web Services C服务端和Java客户端的运行机理,及通过Java客户端访问gSOAP的Web Services的过程中需要注意的问题。

客户根据 WSDL 描述文档,会生成一个 SOAP 请求消息。Web Services 都是放在Web服务器后面,客户生成的SOAP请求会被嵌入在一个HTTP POST请求中,发送到 Web 服务器来。Web 服务器再把这些请求转发给 Web Services 请求处理器。请求处理器的作用在于,解析收到的 SOAP 请求,调用 Web Services,然后再生成相应的 SOAP 应答。Web 服务器得到 SOAP 应答后,会再通过 HTTP应答的方式把信息送回到客户端。
WSDL是Web服务中客户端和服务端沟通的桥梁,描述了对象提供的方法。SOAP帮我们制定了一份被官方认可的对象的封装方法。有了WSDL,客户端只关心如何把参数用Soap封装起来发出去,并获取结果。服务端只关心如何对Soap进行拆包->服务->封包。gSOAP可以帮我们实现上述过程中的拆包和封包,而我们可以只关心服务的实现。

言归正传,在这里我们以一个简单的实现加、减、开放的Web Services的服务为例子,介绍gSOAP的使用:
为了发布这个Web服务,首先我们需要把服务的接口定义好,这个服务可能是一个现有服务的Adapter,为此我们定义头文件
calc.h:

typedef double xsd__double;
int ns__add(xsd__double a, xsd__double b, xsd__double &result);
int ns__sub(xsd__double a, xsd__double b, xsd__double &result);
int ns__sqrt(xsd__double a, xsd__double &result); 

注意到这里面我们把double定义成了xsd__double(两个下划线),这是为了告诉gSOAP,我们需要的soap格式和WSDL格式是基于Document/literal的而非rpc/encoded.为了不把事情搞复杂,在这里我只能说,Java1.6自带的Web Services工具只支持Document/literal格式的WSDL,所以我们生成这种格式的WSDL。至于这两种格式之间选择和他们的long story,大家可以参考下面的文章:
http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/
编写好头文件后,我们就可以利用gSOAP提供的工具进行生成了:
/usr/lib/gsoap-2.7/bin/soapcpp2 -S -2 calc.h
生成的主要文件详见附件。
下面我们实现calc.h中定义的函数:
// Contents of file "calc.cpp": 
#include "soapH.h" 
#include "ns.nsmap" 
#include <math.h> 
int main()
{
   struct soap soap;
   int m, s; // master and slave sockets
   soap_init(&soap);
   m = soap_bind(&soap, "localhost", 9999, 100);
   if (m < 0)
      soap_print_fault(&soap, stderr);
   else
   {
      fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
      for (int i = 1; ; i++)
      {
         s = soap_accept(&soap);
         if (s < 0)
         {
            soap_print_fault(&soap, stderr);
            break;
         }
         fprintf(stderr, "%d: accepted connection from IP=%d.%d.%d.%d socket=%d", i,
            (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF, s);
         if (soap_serve(&soap) != SOAP_OK) // process RPC request
            soap_print_fault(&soap, stderr); // print error
         fprintf(stderr, "request served\n");
         soap_destroy(&soap); // clean up class instances
         soap_end(&soap); // clean up everything and close socket
      }
   }
   soap_done(&soap); // close master socket and detach environment
}
// Implementation of the "add" remote method: 
int ns__add(struct soap *soap, double a, double b, double &result) 
{ 
   result = a + b; 
   return SOAP_OK; 
} 
// Implementation of the "sub" remote method: 
int ns__sub(struct soap *soap, double a, double b, double &result) 
{ 
   result = a - b; 
   return SOAP_OK; 
} 
// Implementation of the "sqrt" remote method: 
int ns__sqrt(struct soap *soap, double a, double &result) 
{ 
   if (a >= 0) 
   { 
      result = sqrt(a); 
      return SOAP_OK; 
   } 
   else
   { 
      return soap_sender_fault(soap, "Square root of negative value", "I can only compute the square root of a non-negative value");
   } 
} 

前文提到过,我们不希望为了发布基于Web Services的C语言的API而开发或应用一个大的Web服务器。我们代码中的main函数实现了一个最简单的Web Server(基于Socket).这个Server利用gSOAP生成的API来提供针对SOAP的处理。
下面我们把这个嵌入式的web server编译,编译的时候注意stdsoap2.cpp这个文件是从gSOAP包中拷贝而来,不是自动生成的,大家下载gSOAP后直接就能找到这个文件及其头文件。
g++ -o calcServer calc.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
一个以Web Servers形式提供的C API诞生了。
在server端执行./calcServer

下面讨论如何用Java1.6的自带工具生成一个客户端stub:
把gSOAP生成的WSDL拷贝到我们的Java开发环境中来,按照Web Services Server中定义的端口和服务器,配置参数生成客户端Web Services代码:
/usr/lib/jvm/jdk1.6.0_03/bin/wsimport -extension -httpproxy:localhost:9999 -verbose ns.wsdl

生成后,把这个环境添加到eclipse的编译环境中来,然后在eclipse中建一个新的类:
class Test {
    public static void main(String args[]) {
        Service service = new Service();
        double h = service.getService().sub(20000, 1);
        System.out.println(h);
    }
}

运行后得到结果19999.0

总结:当集成Java和C两种平台时,我们可以有多种解决方案,但首先我们应该想到gSOAP因为它能够很出色地完成任务。
文中相关代码:
http://www.blogjava.net/Files/yangyi/gsoap.zip
分享到:
评论

相关推荐

    C/C++ API 帮助文档大全(中文,chm格式)

    C/C++ API 帮助文档大全是一份全面的资源,包含了C和C++编程语言的各类API接口和函数的详细信息。这份文档通常以CHM(Compiled Help Manual)格式存在,这是一种由微软开发的、用于存储HTML帮助文档的压缩格式。通过...

    c/c++中文帮助文档(API)

    在C/C++中,API主要由头文件组成,这些头文件定义了库函数的原型,允许程序员在自己的程序中调用这些函数。本资源“c/c++中文帮助文档(API)”为开发者提供了一个全面的参考,帮助他们理解和使用C和C++的各种库函数...

    c/c++ API chm c/c++函数库

    c/c++ API 主要是c/c++函数 c/c++ API 主要是c/c++函数 c/c++ API 主要是c/c++函数 c/c++ API 主要是c/c++函数 c/c++ API 主要是c/c++函数 c/c++ API 主要是c/c++函数 C++ API chm C++ API chm C++ API chm C++ API...

    Dev-cpp5.4.0及API帮助文档 2018年蓝桥杯C语言/c++

    【Dev-Cpp5.4.0】是一款轻量级的C/C++集成开发环境,它为程序员提供了方便的代码编辑、编译、调试等一体化功能。这个版本在2018年的蓝桥杯编程竞赛中被广泛使用,帮助参赛者进行C语言和C++程序的编写。 【C++API....

    Tcl/Tk命令与C/C++的集成研究

    Tcl/Tk命令与C/C++的集成研究 针对Tcl/Tk脚本中需要调用C/C++函数的问题,简要说明了Tcl/Tk命令的运行机理,给出了一个使用Tcl/Tk命令来调用C/C++动态链接库(DLL)函数的方案,并给出了将C/C++DLL函数封装为Tcl/Tk C...

    C/C++ API cppreference API

    C API通常指的是C语言的标准库,如、等头文件中的函数。这些函数包括基本的数据类型操作、内存管理、输入/输出、数学运算等。例如,`printf`用于格式化输出,`malloc`和`free`负责动态内存分配与释放,而`scanf`则...

    API资源.zip(javaAPI+(C/C++API)+windowsAPI)合集(中文版)

    本资源“API资源.zip”是一个集合,包含了三种主要的API:Java API、C/C++ API以及Windows API,均为中文版,对于初学者或者需要深入理解这些API的开发者来说,是一份非常实用的学习资料。 首先,Java API是Java...

    c++ API中文文档

    C运行时库是C++中继承自C语言的部分,包含了一系列的函数,如内存管理(malloc、calloc、free等)、输入/输出(printf、scanf等)和数学运算(如sin、cos等)。这些函数在C++程序中起着基础支持的作用。 C++标准库...

    2021年最新 C/C++中文参考手册

    2021年最新 C/C++中文参考手册

    hdfs c/c++ API头文件

    hdfs c/c++ API, libhdfs库中提供的接口函数声明; 如:hdfsBuilderSetNameNode,hdfsConnect,hdfsOpenFile等

    JAVA C/C++ MFC 中文API chm

    《JAVA C/C++ MFC 中文API chm》是一个综合性的编程参考资料,它涵盖了C++、C和Java这三种主流编程语言的关键API以及MFC(Microsoft Foundation Classes)库的相关知识。对于初学者和有经验的开发者来说,这份资料都...

    精通Matlab与C/C++混合程序设计(第三版) 配套光盘

    4. **内存管理**:由于Matlab和C/C++的内存管理机制不同,理解如何在两者间正确管理内存避免内存泄漏是混合编程中的重要一环。 5. **并发与多线程**:Matlab的并行计算工具箱可以与C/C++的多线程技术结合,实现高...

    C/C++程序设计学习与实验系统

    官方介绍:原名《Turbo C/C++ for Windows 集成实验与学习环境》,支持最新操作系统WINDOWS 7,它是从事一线教学的大学教师根据C/C++ 初学者的特点,量身定制的一个简单易用的 C/C++程序设计学习与实验软件(支持TC2/...

    最全 C/C++ API文档

    来源:cplusplus.com 包含大量使用的实例 适合新手入门学习和老鸟当做工具书参考

    JNI开发Java和C/C++互相传递List集合

    JNI开发Java和C/C++互相传递List集合, 可以参考: Java从C/C++获取List集合对象:https://blog.csdn.net/niuba123456/article/details/80994166 Java传递List集合对象到C/C++ ...

    c/c++ 与java互通 AES加密解密,算法ECB

    最近需要和银行pos做数据通讯,银行端算法为java实现的 AES/ECB/PKCS5PADDING我也改不了, c/c++这边实现ECB算法本来就少,PKCS5PADDING的更是没有,索性自己动手。工作原因c和java都得熟悉,因此把java端和c/c++...

    Java与C/C++的区别(转).

    ### Java与C/C++的主要区别 #### 一、指针机制 在C/C++中,指针是一个重要的特性,提供了底层内存操作的能力。这使得程序员能够直接管理内存资源,但同时也带来了潜在的安全风险,比如野指针问题或内存泄漏等。而...

    C/C++程序设计学习与实验系统 V2008.13.part1

    原名《Turbo C/C++ for Windows 集成实验与学习环境》,现已更名为《C/C++程序设计学习与实验系统》,现在已全面支持最新操作系统VISTA,它由从事一线教学的大学教师根据C/C++初学者的特点,量身定制的一个简单易用的...

    java调用C/C++的例子

    Java调用C/C++是跨语言编程中常见的一种技术,主要通过Java的Native Interface (JNI) 实现。JNI 是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互,尤其是C和C++。在很多情况下,这可以利用现有的...

    MATLAB C/C++, Fortran, Java, and Python API Reference

    《MATLAB C/C++, Fortran, Java, and Python API 参考手册》是MATLAB公司发布的一份技术文档,旨在为使用C/C++, Fortran, Java和Python编程语言与MATLAB进行接口开发的用户提供详细指南。该参考手册覆盖了如何在这些...

Global site tag (gtag.js) - Google Analytics