用gSOAP调用Web Services.docx
- 文档编号:27953952
- 上传时间:2023-07-06
- 格式:DOCX
- 页数:11
- 大小:19.05KB
用gSOAP调用Web Services.docx
《用gSOAP调用Web Services.docx》由会员分享,可在线阅读,更多相关《用gSOAP调用Web Services.docx(11页珍藏版)》请在冰豆网上搜索。
用gSOAP调用WebServices
用gSOAP调用WebServices
1、配置gSOAP
从下载gSOAP,解压后在gsoap\bin\win32里找到wsdl2h.exe和soapcpp2.exe程序。
通过这两个程序可以生成客户端需要的C/C++文件。
这两个程序的使用方法:
wsdl2h.exe:
编译wsdl文件生成c/c++头文件
-o文件名,指定输出头文件
-n名空间前缀代替默认的ns
-c产生纯C代码,否则是C++代码
-s不要使用STL代码
-t文件名,指定typemap文件,默认为typemap.dat
-e禁止为enum成员加上名空间前缀
soapcpp2.exe:
gSOAP编译器,编译头文件生成服务器和客户端都需要的c/c++文件
(如果使用STL,需要从压缩包里找到stlvector.h放到soapcpp2.exe目录下,否则运行失败)
-C仅生成客户端代码
-S仅生成服务器端代码
-L不要产生soapClientLib.c和soapServerLib.c文件
-c产生纯C代码,否则是C++代码(与头文件有关)
-I指定import路径(见上文)
-x不要产生XML示例文件
-i生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)
我写了个批处理:
wsdl2h-oxxxService.h"WSDL文件URL"
soapcpp2-CxxxService.h
如果是asmx,可以在URL后加"?
WSDL"来获取WSDL文件,它是一个XML,用来描述接口,它是与语言无关的,类似COM的IDL文件。
2、创建VC工程,把生成的文件拷到工程目录
生成的文件有:
soapStub.h从输入Header文件生成的经过修改且带标注的Header文件
soapH.h主Header文件,所有客户机和服务源代码都要将其包括在内
soapC.c指定数据结构的序列化器和反序列化器
soapClient.c远程操作的客户机存根例程
stdsoap2.hstdsoap2.cpp运行时库的Header文件
stdsoap2.cpp运行时C++库,带XML解析器和运行时支持例程
创建一个控制台工程:
把上面的几个文件加到工程;
为soapC.c、soapClient.c和stdsoap2.cpp选择Notusingprecompiledheaders,因为它们并不依赖于stdafx.h。
加入wsock32.lib库,这时编译会出现_namespace错误,包含两个文件就可以:
#include"soapServiceSoapProxy.h"
#include"ServiceSoap.nsmap"
3、调用Web服务:
比如服务有个StringgetContext(stringuserName);接口,我们要怎么调用它:
stringusername="heng";
_ns1__getContextgetContext;//调用接口
_ns1__getContextResponsegetContextResponse;//用来接收返回值structsoapsoap;
soap_init(&soap);
getContext.userName=&username;//传入stringuserNameusingnamespacestd;大功造成!
intresult=soap_call___ns2__getContext(&soap,NULL,NULL,&getContext,&getContextResponse);
if(result==SOAP_OK)
{
cout<<"Result:
"<<getContextResponse.getContextResult->c_str()<<endl;//查看返回值
}
else
{
cout<<"Fail!
"<<endl;
}补充,因为用到STL,再加上
#include<string>
另一个版本的!
(基于gsoap-win32-2.7版本,编译环境为VS2005)
客户端
访问自己定义的一个WebService(命名为AddService,对输入的两个整形参数求和,具体服务定义参见AddService.wsdl)
转换WSDL
wsdl2h.exe-s-oAddService.hAddService.wsdl
生成具体调用代码
在命令行输入soapcpp2.exe-CAddService.h
生成代码后,AddService.h就没有用了,不用加入到工程中。
生成的文件
soapStub.hsoapAddServiceSoapBindingProxy.h:
封装了调用webservice的类soapH.hsoapClientLib.cpp:
用不到soapClient.cppsoapC.cppAddServiceSoapBinding.nsmap:
namespaces声明,需要包含在一个cpp文件里面,比如放在StdAfx.cpp里面,否则连接时报错:
unresolvedexternalsymbol_namespaces
还需要stdsoap2.cpp和stdsoap2.h文件,在gsoap-2.7soapcpp2目录下。
注意:
#include“StdAfx.h”加到第一行,否则VC编译报错:
fatalerrorC1010:
unexpectedendoffilewhilelookingforprecompiledheaderdirective
实际调用代码
将这些文件加入到C++工程中,可以使用以下代码调用WebService:
头文件
//包含代理类的头文件
#include"gSoap\soapAddBindingProxy.h"
声明访问代理对象
AddBindingserviceBinding;
设置访问的WebServiceURL
serviceBinding.endpoint=("http:
//LocalHost:
8082/");
调用接口
intiResult;
nRetCode=serviceBinding.__ns1__AddOperation(12,22,iResult);
服务端
实现AddService(对输入的两个整形参数求和)
生成调用代码
同客户端生成方法基本一致。
需要注意的是以下几点:
由.h文件生成具体调用代码:
soapcpp2.exe-SAddService.hsoapClient.cppsoapClientLib.cppsoapServerLib.cpp这三个文件不需要加入到C++工程中。
实现服务线程
在程序开始时,启动服务线程。
UINTGSoapServiceThreadFunc(LPVOIDp)
{
...
}
定义编码格式
//设置UTF-8编码方式
soap_set_mode(&soap,SOAP_C_UTFSTRING);
设置服务的端口号
代码
//端口号
intport=8083;
intbacklog=100;//
intm=soap_bind(&soap,NULL,port,backlog);
if(m<0)
{
strOutput.Format(_T("GSoapServiceThreadFunc——在端口%d上启动服务失败!
"),port);
OutputDebugString(strOutput);
soap_done(&soap);//closemastersocketanddetachenvironment
exit(-1);
}
设置超时
soap.accept_timeout=5;//设置GSoap连接超时,单位:
秒
创建循环,监听,如果有新连接进来则创建请求处理现场
代码
while(TRUE)
{
if(WaitForSingleObject(g_eventTerminateService.m_hObject,0)==WAIT_OBJECT_0)
//结束GSoap服务线程
{
break;
}
ints=soap_accept(&soap);
if(!
soap_valid_socket(s))
{
if(soap.errnum)
{
soap_print_fault(&soap,stderr);
soap_done(&soap);//closemastersocketanddetachenvironment
exit
(1);
}
strOutput.Format(_T("\nGSoapServiceThreadFunc——等待客户端连接超时!
"));
OutputDebugString(strOutput);
}
else
{
strOutput.Format(_T("\n收到来自于IP地址%d.%d.%d.%d的socket连接%d!
"),(soap.ip>>24)&0xFF,(soap.ip>>16)&0xFF,(soap.ip>>8)&0xFF,soap.ip&0xFF,s);
OutputDebugString(strOutput);
structsoap*tsoap=soap_copy(&soap);//makeasafecopy
if(!
tsoap)
{
break;
}
AfxBeginThread(process_request,tsoap);
}
}
实现请求处理线程
相应代码
代码
///GSoap请求处理线程
UINTprocess_request(LPVOIDsoap)
{
CoInitialize(NULL);soap_serve((structsoap*)soap);//会自动调用具体的接口函数
soap_destroy((structsoap*)soap);//deallocC++data
soap_end((structsoap*)soap);//deallocdataandcleanup
soap_done((structsoap*)soap);//detachsoapstruct
free(soap);CoUninitialize();return0;
}
实现接口功能函数
在代码中定义相应的接口功能函数
int__ns1__AddOperation(structsoap*,intA,intB,int&result)
{
result=A+B;
returnSOAP_OK;
}
函数原型在soapStub.h中定义
代码
/******************************************************************************\
**
*ServiceOperations*
**
\******************************************************************************/SOAP_FMAC5intSOAP_FMAC6__ns1__AddOperation(structsoap*,intA,intB,int&result);
现在采用的是默认的命名空间前缀,可以使用typemap.dat文件赋予自定义的命名空间。
常见问题
支持访问wsdl
首先要设置回调处理函数
soap.fget=http_get;
soap.fpost=http_post;
两个回调函数的接口定义(stdsoap2.h)
int(*fpost)(structsoap*,constchar*,constchar*,int,constchar*,constchar*,size_t);
int(*fget)(structsoap*);
根据接口定义实现相应的函数
代码
inthttp_post(structsoap*soap,constchar*endpoint,constchar*host,intport,constchar*path,constchar*action,size_tcount)
{
returnhttp_get(soap);//简单处理,直接调用http_get
}inthttp_get(structsoap*soap)
{
...
}
在http_get函数中解析外部访问路径,并且获取相应的wsdl文件名
代码
//请求WSDL时,传送相应文件
//获取请求的wsdl文件名
stringfielPath(soap->path);
size_tpos=fielPath.rfind("/");
stringfileName(fielPath,pos+1);//将?
替换为.
size_tdotPos=fileName.rfind("?
");if(dotPos==-1)
{
//未找到
return404;
}fileName.replace(dotPos,1,".");
打开WSDL文件发送到客户端
代码
//打开WSDL文件准备拷贝
FILE*fd=fopen(fileName.c_str(),"rb");
if(!
fd)
{
//returnHTTPnotfounderror
return404;
}//HTTPheaderwithtext/xmlcontent
soap->http_content="text/xml";
soap_response(soap,SOAP_FILE);
for(;;)
{
//从fd中读取数据
size_tr=fread(soap->tmpbuf,1,sizeof(soap->tmpbuf),fd);
if(!
r)
{
break;
}//发送数据
if(soap_send_raw(soap,soap->tmpbuf,r))
{
//can'tsend,butlittlewecandoaboutthat
break;
}
}//关闭fd
fclose(fd);
soap_end_send(soap);returnSOAP_OK;
修改命名空间前缀
修改gSoapServer工程使用的命名空间前缀。
在wsdl中的命名空间为“http:
//new.webservice.namespace”
在typemap.dat文件最后添加一行NSNEW="http:
//new.webservice.namespace"
转换wsdl文件时添加参数wsdl2h.exe-ttypemap.dat-s-oAddService.hAddService.wsdl
查看函数原型(soapStub.h),可以看到前缀已经被改变
SOAP_FMAC5intSOAP_FMAC6__NSNEW__AddOperation(structsoap*,intA,intB,int&result);
前段时间学习了一段时间的gsoap,
在网上查找了资料,很多资料都说先由wsdl文件生成.h文件,再由.h文件生成相应的soap相关的依赖文件。
因此一开始花了很多时间去研究wsdl怎
样写。
走入了一个误区。
昨天看到一篇文章后才明白,一开始我就走入了误区。
wsdl是通过gsoap自动生成的。
也就是说再没有wsdl文件的时候可以先定义xxxx.h文件,xxxx.h的定义里面要添加一些说明的语句
//gsoapnsservicename:
severName等项。
然后通过soapcpp2.exexxxx.h来生成wsdl文件等。
如果有可以利用的wsdl文件则可以先生成.h文件再生成soap依赖文件,如:
soapStub.h等。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 用gSOAP调用Web Services gSOAP 调用 Web