易懂易上手WebService客户端——C++之SoapTookit
博客背景介绍:
本是一心想做java工作流,可到公司竟然被指派做C++,C++的任务呢,主要是通信。
这下好了,一个连C++中的HelloWorld都写不出来人,被去写C++程序。呵呵,因为客户的系统是C++版,公司开发工作流是Java版,两者可搭不上话啊,所以哩,C++通信客户端就诞生了。为了协调客户C++与公司Java,C++通信客户端可得发挥其作用了。并且客户C++是C/S结构,而公司Java工作流可是纯纯的B/S结构,所以C++通信客户端这块工作也是需要来协调的。
说到这,想必大家都了解了我目前的工作性质以及C
进入博客主题:
既然被指派,那么只好做下去。不过,工作了十几天,基本上已经适应了。
那就谈谈C++与java通信方式webserice,webserivce不分语言,实际上是一种通信的接口而已。
这篇博客主要讲解一下C++调用WebService,也就是C++作为客户端——soapTookit。
SoapTookit方式比较简单,易懂。并且是自己手写编码,既然是手动编码,则会容易封装。另一种客户端方式gSoap方式,其中个Soap方式使用的命令行工具,命令行工具替我们产生很多头文件,但是个Soap不知如何封装客户端,所以选择了简单易懂的SoapTookit。
使用SoapTookit方式开发WebService客户端,需要安装soapTookit插件。一般安装soapTookit3.0版本。SoapTookit3.0插件会传到网上,方便大家下载。
使用SoapTookit方式开发WebService,编程步骤类似java中的jdbc编程。
首先:创建连接对象。
ISoapConnectorPtr connector; Connector.CreateInstance(__uuidof(HttpConnector30));
第二:指定连接服务器的地址。
Connector->Property ["EndPointURL"]=http://localhost:8080/Test/test;
服务器地址,也就是wsdl文件的地址,地址后面可以添加”?wsdl”
如:Connector->Property["EndPointURL"] =http://localhost:8080/Test/test?wsdl;
第三:真正连接服务器。
Connector->Connect();
第四:指定连接服务器上某个动作(方法)。
封装你访问那个方法,比如求和方法,方法名:sum
Connector->Property ["SoapAction"]= "urn:sum";
为了防止写错,也可以写成与第二步一样,直接写wsdl路径。
如:Connector->Property["SoapAction"]= “http://localhost:8080/Test/test”
第五:给第四步中的方法中传递消息(传递参数赋值——输入流)
// 创建SoapSerializer对象,并用InputSTream进行初始化。 ISoapSerializerPtr Serializer; Serializer.CreateInstance(_uuidof(SoapSerializer30)); Serializer->Init(_variant_t((IUnknown*)Connector->InputStream)); //真正发送消息 Serializer->startEnvelope("","",""); // 开始处理SOAP消息。第一个参数是命名空间,缺省为SOAP-ENV。 // 第二个参数定义URI。第三个参数定义Serialzier->startBody("")函数的编码方式。 // 开始处理<Body>元素,第一个参数是URI的编码类型,缺省为NONE。 Serializer->StartBody("");Serializer->StartElement("sum","http://sum","","m"); // 开始处理Body里的子元素。 // 第一个参数是元素名。第二个参数是URI。 // 第三个参数编码类型。第四个参数是元素的命名空间。Serializer->StartElement("a","","","");Serializer->WriteString("10");Serializer->EndElement();Serializer->StartElement("b","","","");Serializer->WriteString("20");Serializer->EndElement(); Serializer->EndElement();Serializer->EndBody();Serializer->EndEnvelope();仔细观察,可以发现,start与end是匹配的。
第六:读取服务器返回值(输出流方式)
ISoapReaderPtr Reader;Reader.CreateInstance(__uuidof(SoapReader30));// Connect the reader to the output stream of the connector object. Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");// Display the result. printf("Answer: %s\n", (const char*)Reader->RpcResult->text);
开发过程中,需要注意的几个事项:
若返回的结果是:soap server,说明没有匹配上,比如参数名称不对或者输入参数不合格,没有相应的结果。
输入参数中,writeString,只能输出string类型。在c++中输入字符数组或者字符串指针形式。
若是输入参数是int,或long类型,还必须转化成char数组形式或char*形式。
在转化的过程中,注意long或int在内存的长度。
输出结果时,不能只能return (constchar*)Reader->RpcResult->text,因为方法结束后,指针也消亡了,所以会提示错误。需要把结果赋值copy到一个字符串中,然后再返回。
若是返回int或long类型时,则再次由char*转化成int或long类型。
若方法中参数是数组,如何传输呢?
只要把参数名写一样,即可。比如上述sum方法中a是数组参数,则:
Serializer->StartElement("a","","","");Serializer->WriteString("10");Serializer->EndElement();Serializer->StartElement("a","","","");Serializer->WriteString("10");Serializer->EndElement();
在操作中,需要引入soapTookit3.0中相应的dll表头文件。
#import "msxml4.dll" using namespace MSXML2;//mssoap3.0.dll路径(视情况而定)#import"C:/ProgramFiles/CommonFiles/MSSoap/Binaries/mssoap30.dll" /exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", /"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")using namespace MSSOAPLib30;
所谓的注意事项,是在开发过程中经验吧。SoapTookit插件以及demo源码,我会及时上传的。
后期会继续总结开发webserivce客户端另一种方式gsoap以及开发webserivce服务器端方式gsoap,并且会详细阐述在开发遇到的问题以及解决的方案。