java和c+的webservice互调用

来源:互联网 发布:mac一直显示flash过期 编辑:程序博客网 时间:2024/05/20 05:28

了解:

     各种接口参考:http://www.haoservice.com/apilist/

Gsoap 编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,

从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。

用gsoap开发web service的大致思路

我们开发webservice应用,大致有两个方向:

1.  API接口固定,不关心底层的通讯,将SOAP作为应用层协议

此时,我们先定义接口,编写好.h文件,运行soapcpp2生成出相应的代码,对服务器端,修改XXXService文件,实现业务逻辑,对客户端,修改XXXProxy文件,实现业务逻辑。

2.  通讯协议固定(当然需要基于XML的)或只有wsdl,将SOAP作为“传输层”协议

此时,我们必须根据通讯协议或wsdl生成相应的C/C++类型的.h文件,如果需要我们自己编写wsdl,则需要一点其相关知识,不过我们可以用C#等生成一个简单的wsdl,照猫画虎即可。运用wsdl2h,我们可以生成.h文件,有了.h后,按上面的步骤继续。

(注意:有时通过wsdl2 *.wsdl 命令生成的*.h头文件会默认包含stlvector.h,所以编译包里必须包含这个文件才能用soap2 *.h 命令编译生成文件)

一、根据WSDL文件开发WebService客户端,访问Java的WebService服务端

1. Java 定义好WebService接口,生成WSDL标准接口文件。

2. 使用GSoap的WSDL2h.exe工具把WSDL文件生成C++的头文件

    wsdl2h  XXX.wsdl 命令会生成 XXX.h

3. 使用GSoap的 soapcpp2.exe工具把XXX.h头文件生成Soap封装的类

    soapcpp2 -C -p XXX -j  XXX.h

    -C为生成客户端代码,会生成以Proxy结尾的类, 

    -S为生成服务端代码,会生成以Service结尾的类。

WSDL标准接口文件的解析说明可参考WSDL相关资料。

注意:根据WSDL文件生成的客户端的接口返回值也是是int类型,返回结果被GSoap封装为接口的引用参数了。

二、根据.h头文件开发C++的WebService服务端,Java用客户端访问

1.定义APi接口函数

如:calc.h文件接口编写

    //calculater

//gsoap api service name:  calc

//gsoap api service style:

//gsoap api service encoding:

//gsoap api service location:

//gsoap api service namespace:

//gsoap api schema namespace:

typedef char*

typedef int     xsd__int;

    //加法接口
    int api__add
    (
     xsd__int num1,
     xsd__int num2,

 xsd__string desc,

 xsd__int & result

    );

2.直接用build.bat脚本编译成功后便会生成WS请求的WSDL接口文件

使用soapcpp2命令编译:

soapcpp2 -S -p calc -j calc.h  生产服务端代码

3.编写类继承生成的接口类就可以实现其功能,

或者把用全局函数ns__add(int num1,int num2,string desc, int result)实现接口功能。

4.包含文件:头文件,命名空间文件,soap组件文件

#include "soap/calcH.h"

#include "soap/calc.nsmap"

#include "soap/stdsoap2.h"

5.问题:其自定义生成接口在生成类中没有添加实现,编译报链接错误?

生成类源文件中实现自定义的接口函数,放空,编译通过。

6.测试:使用SoapUi工具建立工程,加载到WSDl文件,其端口号要与监听的端口一致。

注意:服务端的接口返回值必须是int类型,如果需要返回结果其它信息需要使用引用参数,

引用参数可以是基础类型,或者自己封装的结构体类型。


1、http://blog.csdn.net/a9529lty/article/details/8504324

java客户端调用C++ GSoap生成的webservice

package com.test.webservice.client;import java.rmi.RemoteException;import javax.xml.namespace.QName;import javax.xml.rpc.ServiceException;import org.apache.axis.client.Call;import org.apache.axis.client.Service;public class TestClent {public static void main(String[] args) {try {String endpoint = "http://www.cmsz.com:7088/getdbpwd/getdbpwdservice"; Service service = new Service(); Call call = (Call)service.createCall(); call.setTargetEndpointAddress(endpoint);call.setOperationName(new QName( "urn:getdbpwd", "getdbpwd")); call.addParameter( "pmsDBUser",null,javax.xml.rpc.ParameterMode.IN); call.setReturnClass(String.class); String temp = (String)call.invoke(new Object[]{"pubdba"}); System.out.println("result: " + temp);} catch (ServiceException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

对应的WSDL 文件是C++服务端生成的,如下:

<?xml version="1.0" encoding="UTF-8"?><definitions name="getdbpwd" targetNamespace="http://www.cmsz.com:7088/getdbpwd/getdbpwd.wsdl" xmlns:tns="http://www.cmsz.com:7088/getdbpwd/getdbpwd.wsdl" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="urn:getdbpwd" xmlns:SOAP="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:MIME="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:DIME="http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/" xmlns:WSDL="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"><types> <schema targetNamespace="urn:getdbpwd"  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsd="http://www.w3.org/2001/XMLSchema"  xmlns:ns="urn:getdbpwd"  xmlns="http://www.w3.org/2001/XMLSchema"  elementFormDefault="unqualified"  attributeFormDefault="unqualified">  <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"/> </schema></types><message name="getdbpwdRequest"> <part name="pmsDBUser" type="xsd:string"/></message><message name="getdbpwdResponse"> <part name="password" type="xsd:string"/></message><portType name="getdbpwdPortType"> <operation name="getdbpwd">  <documentation>Service definition of function ns__getdbpwd</documentation>  <input message="tns:getdbpwdRequest"/>  <output message="tns:getdbpwdResponse"/> </operation></portType><binding name="getdbpwd" type="tns:getdbpwdPortType"> <SOAP:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getdbpwd">  <SOAP:operation style="rpc" soapAction=""/>  <input>     <SOAP:body use="encoded" namespace="urn:getdbpwd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>  </input>  <output>     <SOAP:body use="encoded" namespace="urn:getdbpwd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>  </output> </operation></binding><service name="getdbpwd"> <documentation>gSOAP 2.7.15 generated service definition</documentation> <port name="getdbpwd" binding="tns:getdbpwd">  <SOAP:address location="http://www.cmsz.com:7088/getdbpwd/getdbpwdservice"/> </port></service></definitions>

2、c++ 使用 gsoap 调用 java WebService

问题描述:
    使用gsoap时,如果WebService服务端及客户调用端都使用 C++ , 再传递中文时不会存在乱码问题,
    当客户端为 C++ ,WebService服务端使用Java、domino,传递中文则会有乱码问题。

产生原因:
    宽字符的原因,

解决办法(一):
    在程序中首先设置本地代码页
    vista 操作系统:  
          setlocal(LC_ALL,"Chinese");
          soap_set_mode(soap,SOAP_C_MBSTRING);
    windowsxp 操作系统:
          setlocal(LC_ALL,"chs");
          soap_set_mode(soap,SOAP_C_MBSTRING);

解决方法(二)
    1. 使用 wsdl2h.exe 通过wsdl描述文件创建C++头文件(test.h);
    2. 将头文件(test.h)中 std:string* 使用wchar_t* 替换;
    3. 使用 soapcpp2.exe -i test.h ,生成相关的cpp及h文件
    4. 使用 C++ 时,需要将接收的wchar_t类型数据转换为char, 使用WideCharToMultiByte函数   

后续:
    soap在对字符编码转换时,调用 wctomb 函数,该函数的调用在 stdcoap2.cpp 文件中,代码调试跟踪至此,查看 该函数的返回值是否正确,-1表示字符集设置不正确。


参考2:C/C++调用Web Service需要用到soap库,一般使用的有gsoap和axis cpp两种实现,这里使用gsoap来调用。gsoap是sourceforge上的一个开源项目,目前版本是2.7.6c,使用简单,可以在linxu、windows、mac多种平台上使用。gsoap的主页地址是http://gsoap2.sourceforge.net/

gsoap使用步骤

gsoap提供了两个有用的工具,帮助我们生成代理类。

实际用到的源码

gsopa所有源码在stdsoap2.c /stdsoap2.cpp和stdsoap2.h中,编译目标文件时要根据实际使用的语言来选择stdsoap2.c/cpp

使用wsdl2h生成函数描述

wsdl2h -c -o message.h http://***/messageservice.asmx?wsdl
message.h表示根据http://***/messageservice.asmx?wsdl输出函数描述文件为message.h

-c 参数表示用纯c语言来实现,如果不加-c,则用c++语言来实现

使用soapcpp2来生成代理函数

下面的命令根据刚产生的message.h文件来生成代理类/函数:

soapcpp2 -c message.h
执行后,会产生若干个h文件和c文件,里面包含了对远程函数的封装。
本例中生成了以下文件: soapH.h soapServer.c soapServerLib.c soapClient.c soapClientLib.c soapStub.h soapC.c MessageServiceSoap.nsmap

做为web service调用方,实际使用到的stdsoap2.c soapC.c soapClient.c这几个文件(包括对应头文件),MessageServiceSoap.nsmap实际上是一个头文件,定义了soap相应的namespace.

使用生成的代理类/函数

将代码保存为client.c

        
#include "soapH.h"
#include "MessageServiceSoap.nsmap"
int main()
{
        struct soap *soap = soap_new();
        struct _ns1__SendSMSResponse out;
        char * url = "http://***/MessageService.asmx";
        struct _ns1__SendSMS msg;
        msg.sender = "900";
        msg.receiver = "mic";
        msg.title = "test";
        msg.msgInfo = "testinfo";
        msg.messageType = 0;
   soap_set_mode(soap, SOAP_C_UTFSTRING);  //设置soap编码为UTF-8,防止中文乱码
        if(soap_call___ns1__SendSMS(soap, url, "http://***/common/message/SendSMS", &msg, &out) == SOAP_OK)
        {
                printf("OK");
        }
}
      编译目标

gcc -o msg stdsoap2.c soapC.c soapClient.c client.c stdsoap2.c
更多使用例子,可以查看gsoap附带的sample目录。
编码转换的例子,保证使用utf8传输
int GBKtoUTF8(char *fromstr,size_t fromlen,char *tostr,size_t tolen)
{
    int r;  
    iconv_t cd;

    if ((cd = iconv_open("GBK","UTF-8")) == (iconv_t)-1) {
        fprintf(stderr, "iconv_open from UTF to GBK error: %s/n", strerror(errno));
        return -1;
    }

    r = iconv(cd,&fromstr,&fromlen,&tostr,&tolen);
    if (r < 0) {        
        fprintf(stderr, "iconv from UTF to GBK error: %s/n", strerror(errno));
        iconv_close(cd);
        return -2;
    }

    iconv_close(cd);
    return 0;
}






0 0