我的gsoap创建客户端网络代理过程

2017年06月11日16:42:58

创新互联建站主要从事网站制作、成都做网站、网页设计、企业做网站、公司建网站等业务。立足成都服务朔城,10年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:13518219792

这几天做了一个售电接口(windows平台下),包括webservice服务(C#)、webservice动态库、客户端dll(C++)、客户端gsoap代理。软件结构如下:

clientDLL(客户端机器)---->gsoapProxy(客户端机器)------>webservice(服务器)--->webserviceDLL(服务器)---->HSM(加密机)

【强调一下前提,webservice服务是用vs2010创建的web工程,而client是C/C++写的,这里主要介绍如何使用gsoap代理client请求】

由于客户端和服务器不是在同一台机器上,所以使用直接动态调用dll已不可能。C/C++要通过网络去连接服务器,将函数参数传输到webservice的对应函数接口中,就必然要使用某种工具来将函数参数转换到网络格式传输到server,gsoap就是这种强大的工具。gsoap不仅可以代理客户端请求,还可以代理服务端(本次只使用其作为客户端代理)。虽然其已经尽可能做到简单易用,但是我在网络上搜索了好多文章,都是教到生成出文件为止,而如何使用生成出的文件,都是不甚了了。所以我将整个使用过程记录下来,方便以后借鉴。

(一)  下载gsoap软件,网上搜一下,去官方下,然后解压出来,一定要看是否解压完全,在其根目录下有3个文件stdsoap2.h、stdsoap2.cpp 、stdsoap2.c,这个后面要用到的。(我的就是解压过程中电脑好像死机了,但是我没注意,然后没有解压完,害的找了半天stdsoap2这个文件)

(二)生成中间文件

在解压出来的目录下找到wsdl2h.exe   soapcpp2.exe两个文件。

2.1 首先生成中间头文件,作用就是将你的服务端暴露出来的接口生成按网络格式的函数形式。打开命令行窗口,进入到gsoap目录下:【我用的C++方式】

wsdl2h  -s  -o   test.h   http://xxxxx:xxxx/xxx.wsdl

wsdl2h常用选项

  • -o 文件名,指定输出头文件

  • -n 名空间前缀 代替默认的ns

  • -c 产生纯C代码,否则是C++代码

  • -s 不要使用STL代码

  • -t 文件名,指定type map文件,默认为typemap.dat

  • -e 禁止为enum成员加上名空间前缀

后面的***.wsdl是服务端接口说明。如何找到它呢?就我的项目而言,是这样的:

我的webservice是用c#写的,直接使用vs2010创建的web工程,【运行该工程】,就会启动一个web服务了,会弹出浏览器打开一个页面,点击" *****.asmx ",会看到所有的web接口,然后页面上有一个“查看说明”字样的链接,点击应该会进入到 "  ****.wsdl "了,对,就是它。

2.2  根据头文件生产其他文件

soapcpp2  -j  test.h  

soapcpp2常用选项

  • -C 仅生成客户端代码

  • -S 仅生成服务器端代码

  • -L 不要产生soapClientLib.c和soapServerLib.c文件

  • -c 产生纯C代码,否则是C++代码(与头文件有关)

  • -I 指定import路径(见上文)

  • -x 不要产生XML示例文件

  • -i生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。

  • -j 和-i类似,区别在于生成的代理类不继承于soap struct,而是包含了一个soap的指针。此种方式生成的代理类便于相互通信

将生成下面这些文件

  • soapStub.h// soap的存根文件,定义了test.h里对应的远程调用模型

  • soapC.csoapH.h //soap的序列和反序列代码,它已经包含了soapStub.h,服务器端与客户端都要包含它

  • soapClient.csoapClientLib.c //C客户端代码,soapClientLib.c文件则只是简单地包含soapClient.c和soapC.c

  • soapServer.csoapServerLib.c //C服务器端代码,soapServerLib.c文件则只是简单地包含soapServer.c和soapC.c

  • ServiceSoap.nsmapServiceSoap12.nsmap // 名空间定义,服务器端与客户端都要包含它

  • soapServiceSoapProxy.hsoapServiceSoap12Proxy.h //客户端的C++简单包装(如果头文件是纯C代码,这两个文件就不会生成)

综上所述

  • 如果编写服务器端C方式,需要的文件就有:soapStub.h、soapC.cpp  soapH.h  soapServer.c  soapServerLib.c  ServiceSoap.nsmap  ServiceSoap12.nsmap  soapServiceSoapProxy.h  soapServiceSoap12Proxy.h

  • 如果编写客户端C++方式,需要的文件就是:soapStub.h  soapC.cpp  soapH.h  soapXXXXSoapProxy.cpp  soapXXXXSoapProxy.h  soapXXXXSoapService.cpp  soapXXXXSoapService.h  XXXXSoap.nsmap

  • 当然,还要加入gsoap库里的stdsoap2.cpp文件(如果是写C代码,则加入stdsoap2.c)【在gsoap根目录下,不同版本的gsoap对应的该文件是不同的,不可以混用】

  • 到这里test.h已经没用了

如果看到soapcpp2提示:”Criticalerror: #import: Cannot open file "stlvector.h" forreading.“, 那是因为我们的头文件使用了STL(wsdl2h没用-s选项),这时要使用-I选项指定gSOAP的import文件路径,这个路径是"$gsoap\gsoap\import":

soapcpp2   -j  test.h -I D:\gsoap-2.7\gsoap\import

(三) 创建代理,入参出参转换,接收返回值

gsoap会将你的服务端接口进行名字转换,而且分成请求和响应两个class(我使用的是C++方式,用起来感觉更简单一些)。

例如:服务端接口为 int  EncryptPurse(char* cardNum, char*  fileMoney, char* dataOut);

gsoap会将该接口转换为:

_ns1__EncryptPurse   【请求类,传递入参】

_ns1__EncryptPurseResponse 【响应类,获取出参和返回值】

创建soap结构体和gsoap代理:

struct  soap  soap;

HSM_USCOREEPSaleSoapProxy  soapProxy; // 类型名字会有不同

定义soap的数据传输格式:

soap_init(&soap);  //Initializes a runtime context

soap_set_mode(&soap, SOAP_C_MBSTRING); //设置数据模式

soapProxy.HSM_USCOREEPSaleSoapProxy_init(SOAP_C_MBSTRING, SOAP_C_MBSTRING);//初始化数据传输模式

然后进行参数转换,注意入参和出参分别在两个类中:

_ns1__EncryptPurse    reqEncryptPurse; //创建请求类对象

_ns1__EncryptPurseResponse  respEncryptPurse;  //创建响应类对象

reqEncryptPurse.cardNum = IncardNo;  // IncardNo为实际传入的参数

reqEncryptPurse.fileMoney = InfileMoney; //InfileMoney为实际传入的参数

respEncyptPurse.dataOut = Outdata;// Outdata为接收出参的参数

接下来调用接口:

int  ret  = soap.EncryptPurse("http://localhost:1132/EPSaleWebService.asmx", NULL, &reqEncryptPurse, respEncryptPurse);

接收返回值和出参

ret =respResponse.EncryptPurseResult;  //接收EncryptPurse的返回值

strcpy(dataOut, respEncryptPurse.dataOut); //接收出参的值

关闭soap,清理内存:

soap_close(&soap);

soap_end(&soap);

soap_done(&soap);

到这里,一个函数接口的请求和相应就完成了.

遇到的问题:

1.最开始编写gsoap工程用的vc6,在编译时报错:sockaddr_storage未定义的类型

由于winsock的版本不一致导致,改到vs2010里再编译就没有该问题了。如果非要在vc6里编译,请继续百度,应该有其他解决方案.

2.error LNK2001: 无法解析的外部符号 _namespaces

  工程--属性--配置属性---C/C++---预处理器, 添加 WITH_NONAMESPACES


本文名称:我的gsoap创建客户端网络代理过程
当前路径:http://pwwzsj.com/article/jcpehe.html