了解:
各种接口参考: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文件接口编写
//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;
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 block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.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;
}