C++中使用soap toolkit访问webService详解
使用Visual C++开发SOAP客户端应用
简介
在本篇文章中,我们将讨论如何使用Visual C++开发一个简单的SOAP客户端应用程序,我们还将介绍SOAP API的使用。SOAP是互联网上一种非常流行的交换信息用的协议,由于是为了与HTTP、SMTP和其他的类似协议协同工作的,因此它十分简单。用它描述的信息能够被轻易地通过互联网发送到另外的计算机上,而无需担心遭到防火墙等网络安全技术的拦截。
在这里,我们假设读者已经对SOAP协议有了一定的理解,而且对C++比较精通。如果读者对SOAP还不熟悉,可以查看相关的资料。我们还假设读者熟悉COM的使用,特别是COM中的智能指针,因为在这篇文章中,我们将使用导入命令将COM接口转换为智能指针。另外,读者还需要安装了微软的SOAP工具包。
SOAP编程基础
我们将以介绍一个与基本的SOAP应用程序有关的类开始我们的SOAP编程之旅。然而,我们还必须首先导入必需的类型库,我们的应用程序才能使用SOAP类。
导入类型库
SOAP中使用的所有对象和接口都包含在mssoap1.dll中,这个文件包含在Microsoft SOAP Toolkit 2.0中。我们可以在C:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll中发现该文件。使用#import命令就可以将该文件导入到我们的源文件中。类库文件中的内容将被转换为描述了COM接口的COM智能指针。
SOAP使用XML作为其数据格式,因此我们还需要微软的XML Parser来处理XML内容,它包含在msxml3.dll中。在导入mssoap1.dll文件之前,我们还需要导入该文件,如下所示:
#import "msxml3.dll"
using namespace MSXML2;
#import "C:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll" \
exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib;
上面是开发一个SOAP应用程序所必需包含的所有类定义。开发一个SOAP客户端应用程序需要三个步骤:
·指定并连接一个互联网服务。
·准备并发送消息。
·读取来自服务器的响应。
下面是我们用来开发一个基本的SOAP客户端应用程序所需要用到的类:
SoapConnector
在客户机/服务器模式中任何客户端应用程序需要作的第一件事就是与服务器进行连接。SoapConnector就是被用来实现客户机端、服务器端应用程序连接器的协议,它还充当定义实现其他协议接口的抽象类,也就是说,SOAP不仅仅局限于充当一种特定的协议。我们会发现,它的一些实现还支持MSMQ、MQ Series、SMTP和TCP/IPTransports。为了简单起见,我在这里只讨论它作为HTTP Transport的用途,这是由微软SOAP Toolkit 2.0中的HttpConnector类实现的。
使用SoapConnector类所需要的步骤
首先,创建SoapConnector类的一个对象:
ISoapConnectorPtr connector; Connector.CreateInstance(__uuidof(HttpConnector));
然后,指定Web服务的地址。接下来,我们必须详细描述该Web服务。Web服务是由Property(HttpConnector的一个属性)指定的。在处理这一属性时有件事情需要指定:我们引用的哪个属性以及该属性的值。下面,我们使用EndPointURL属性指定Web服务:
Connector->Property ["EndPointURL"] = "some url pointing to web service";
下面的表格提供了一个属性清单(属性的名字是大小写敏感的)
属性 描述
AuthPassword 端点认证用的口令。
AuthUser 端点认证用的用户名。
EndPointURL 端点的URL。
ProxyPassword 代理认证的口令。
ProxyPort 代理服务器使用的端口。
ProxyServer 代理服务器的主机名或IP地址。
ProxyUser 代理认证的用户名。
SoapAction HTTP头部中SoapAction中的值。这一属性只能从低级的API中设定,如果使用SoapClient接口中的ConnectorProperty属性(高级API)设置该属性,它就会被忽略。
SSLClientCertificateName 如果存在,则该字符串标明用于SSL协议中的客户端证书。其语法为: SSLClientCertificateName [CURRENT_USER | LOCAL_MACHINE\[store-name\]]证书名,其缺省的名字为 CURRENT_USER\MY。
Timeout HttpConnector的超时时间,这一时间是以毫秒计算的。
UseProxy 一个类型为布尔型的属性,表明是否使用代理服务器。缺省情况下,这一属性的值被设定为False,表明无需使用代理服务器。如果要使用代服务器,需要将该属性的值设置为True。如果将该属性的值设置为True, 而又没有设置ProxyServer属性,HttpConnector将使用IE中设置的代理服器。HttpConnector会忽略IE中的“不使用代理服务器”设置。
UseSSL 表明是否使用了SSL的布尔型值。如果该属性被设置为True,则无论WSDL中是否指定了HTTP或HTTPS,HttpConnector对象都使用SSL连接。
如果该属性的值被设置为False,则只有在WSDL中指定了HTTPS的情况下, HttpConnector对象才会使用SSL连接。
其次,我们需要与Web服务连接。HttpConnector类的Connect方法用来初始化SoapConnector对象和准备与Web服务的连接。
Connector->Connect();
在与服务器连接后,我们需要指定Web服务完成的操作。为了指定该操作,我们需要再次使用SoapConnector的Property属性:
Connector->Property ["SoapAction"] = "some uri";
在完成与Web服务的连接和其他的细节后,我们就可以调用向服务器发送SOAP信息的方法了,必须在调用SoapSerializer的其他方法之前调用该方法:
Connector->BeginMessage();
在完成与信息相关的操作后,我们必须调用EndMessage()函数,将消息真正地发给Web服务。.
.
[ 消息准备代码 ]
.
.
Connector->EndMessage();
上面的步骤就是完成与Web服务的实际连接所必需的操作。在下面的部分,我们将讨论如何创建和准备一个信息。
SoapSerializer
SoapSerializer对象用来构建一个向Web服务发送的SOAP消息。在与服务器连接前,SoapSerializer对象必须与SoapConnector对象连接。为了使这二个对象相互连接,我们需要调用SoapSerializer对象的Init方法,该方法需要一个参数InputStream(向服务器发送数据的流):
// 创建一个SoapSerializer对象,并使用InputSTream对它进行初始化
ISoapSerializerPtr Serializer; Serializer.CreateInstance(_uuidof(SoapSerializer)); Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
在讨论SoapSerializer的其他函数以前,我们来看一个SOAP请求的例子:
<SOAP: Envelope xmlns:SOAP="soap namespace">
<SOAP:Body>
<m:someMethodName xmlns:m="some namespace">
<someParameter> someParameterValue </someParameter>
<m:someMethodName>
</SOAP:Body>
</SOAP: Envelope>
SOAP请求被封装在了标记中。<Envelope>标记是该SOAP文档的主标记,SOAP消息通常都被封装在<Envelope>元素中,<Envelope>元素包含一个由<Body>标记指定的消息体,该消息体包含着实际的请求。在C++中,有非常合适的方法可以创建这些标记并指定其值。下面的代码说明了如何利用这些方法:
Serializer->startEnvelope("SOAP","","");
// 开始SOAP消息中的一个元素,第一个参数描述了名字空间,
// 如果它是空值,就会缺省地使用SOAP-ENV。第二、第三个参数
// 分别描述了URI和编码类型。
Serialzier->startBody("");
// 消息中<Body>元素的开始,第一个参数描述了编码风格Uri,其缺省的值为NONE。
Serializer->startElement("someMethodName","","","m");
// SOAP消息中<Body>元素的子元素的开始。第一个参数是子元素名字
//第二个参数是URI,第三个参数是编码类型,最后一个参数是元素的名字空间。
Serializer->WriteString("someParameterValue")
// 写元素的值
上面以startXXX开头的函数都相应地有以endXXX开头、结束元素的函数。在完成消息后,系统会调用连接的endMessage()方法,真正开始向服务发送消息。
现在我们已经与服务相连接,准备好了我们的请求,并将它发送给了服务。最后一个步骤就是读取来自服务器的响应。下面我们就来讨论这一问题。
SoapReader
该对象读取来自Web服务的响应,并将它解析为DOM,以备进一步处理之用。下面是一个来自Web服务的响应的例子:
<SOAP: Envelope xmlns:SOAP="soap namespace">
<SOAP:Body>
<m:someMethodNameResponse xmlns:m="some namespace">
<return> someResult </return>
<m:someMethodNameResponse>
</SOAP:Body>
</SOAP: Envelope>
在调用任何方法获取结果前,我们联接OutputStream,读取存储在SoapReader对象中的响应(OutputStream用于接收来自Web服务的数据):
// 创建SOAPReader对象和与outputstream联接的代码
ISoapReaderPtr Reader; Reader.CreateInstance(_uuidof(SoapReader)); Reader->Load(_variant_t((IUnknown*)Connector->OutputStream));
// load方法也能够接收XML文档文件或字符串
在将Web服务的响应加载到SoapReader对象后,我们可以通过调用SoapReader对象的RPCResult属性获得相应的结果,但RPCResult并不返回真正的结果,它返回的是<Body>元素中第一个条目的第一个子元素。我们可以通过调用text属性返回真正的结果:
Reader->RPCResult->text
一个SOAP客户端应用程序的例子
为了说明如何使用本篇文章中讨论的SOAP类,我们使用了http://www.xmethods.net/上列出的一项服务,该服务能够显示用户是否正在使用Yahoo Messenger。它只需要一个参数,即Yahoo用户的登录ID。返回的结果是一个布尔型值,0表示用户不在线,1表示用户在线。
我一直认为,学习某种编程技术的最好的方法就是实地学习源代码,在这里,我们就采取这种方法。下面是使用SOAP调用发现Yahoo用户是否在线的一个控制台应用程序的C++代码:
#include
#import "msxml3.dll"
using namespace MSXML2;
#import "C:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll" \
exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib;
void main()
{
CoInitialize(NULL);
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapConnectorPtr Connector;
// 与Web服务连接
Connector.CreateInstance(__uuidof(HttpConnector));
Connector->Property["EndPointURL"] = "http://www.allesta.net:51110/webservices/soapx4/isuseronline.php";
Connector->Connect();
// 开始消息
Connector->Property["SoapAction"] = "uri:allesta-YahooUserPing";
Connector->BeginMessage();
// 创建SoapSerializer对象
Serializer.CreateInstance(__uuidof(SoapSerializer));
// 将serializer连接到connector的输入字符串
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
// 创建SOAP消息
Serializer->startEnvelope("","","");
Serializer->startBody("");
Serializer->startElement("isuseronline","uri:allesta-YahooUserPing","","m");
Serializer->startElement("username","","","");
Serializer->writeString("laghari78");
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
// 将该消息发送给web服务
Connector->EndMessage();
// 读取响应
Reader.CreateInstance(__uuidof(SoapReader));
// 将reader联接到connector的输出字符串
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");
// 显示结果
printf("Answer: %s\n", (const char *)Reader->RPCResult->text);
CoUninitialize();
}
我们可以看到,代码十分简单,即使没有使用过C++,我保证读者也能够理解上面代码的作用:首先,它与远程服务器连接;其次,它创建SOAP消息并向web服务发送该消息;最后,读取服务器的响应,并使用printf将它输出到屏幕上。
结论
在本篇文章中,我们讨论了如何使用Visual C++建立一个简单的SOAP客户端应用程序。我们还学习了SOAP Toolkit中的几个方法以及如何使用SOAP从服务器获取数据。希望通过本篇文章,使读者能够掌握如何使用C++开发SOAP客户端应用程序。
C++中使用soap toolkit访问webService详解的更多相关文章
- 在ASP.NET中使用SOAP Extensions捕获WebService异常
原文:在ASP.NET中使用SOAP Extensions捕获WebService异常 Application_Error不能捕获的异常 [WebMethod] public string Hello ...
- 基础拾遗------webservice详解
基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...
- Axis2开发webservice详解
Axis2开发webservice详解 标签: javawebserviceAxis2 2015-08-10 10:58 1827人阅读 评论(0) 收藏 举报 分类: JAVA(275) 服务器 ...
- Java中堆内存和栈内存详解2
Java中堆内存和栈内存详解 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...
- Scala 深入浅出实战经典 第62讲:Scala中上下文界定内幕中的隐式参数实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- 在ASP.NET 5应用程序中的跨域请求功能详解
在ASP.NET 5应用程序中的跨域请求功能详解 浏览器安全阻止了一个网页中向另外一个域提交请求,这个限制叫做同域策咯(same-origin policy),这组织了一个恶意网站从另外一个网站读取敏 ...
- SpringBoot中使用UEditor基本配置(图文详解)
SpringBoot中使用UEditor基本配置(图文详解) 2018年03月12日 10:52:32 BigPotR 阅读数:4497 最近因工作需要,在自己研究百度的富文本编辑器UEditor ...
- Android 中各种权限深入体验及详解
Android 中各种权限深入体验及详解 分类: Android2012-07-15 19:27 2822人阅读 评论(0) 收藏 举报 androidpermissionsinstallersyst ...
- java中List的用法和实例详解
java中List的用法和实例详解 List的用法List包括List接口以及List接口的所有实现类.因为List接口实现了Collection接口,所以List接口拥有Collection接口提供 ...
随机推荐
- STM32上使用JSON
一.STM32工程中添加JSON 最近在一网2串项目,串口和网口之间可能需要定义一下简单的通信协议,而通信协议上则需要去定义一下通信的数据格式,上次听剑锋说要用Json来定义,目前查了下资料具体如何去 ...
- 平衡数之Treap
#include <memory>//智能指针头文件 #include <random>//随机数头文件 #include <iostream> #include ...
- BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap
题意:链接 方法: Treap 解析: 前几道资格赛的题水的不行,这道Gold的题就够分量辣. 首先这个曼哈顿距离啥的肯定能做文章,怎么转化是个问题,自己玩了一会没玩出来,就查了查曼哈顿距离的转化,发 ...
- JavaScript作用域闭包(你不知道的JavaScript)
JavaScript闭包.是JS开发project师必须深入了解的知识. 3月份自己曾撰写博客<JavaScript闭包>.博客中仅仅是简单阐述了闭包的工作过程和列举了几个演示样例,并没有 ...
- ViewPager 入门一
使用ViewPager能够得到不同view的切换效果 例如以下图,实现了四个view间的相互滑动 一.新建项目,引入ViewPager控件 ViewPager.它是google SDk中自带的一个附加 ...
- animation- 动画效果实现(xml形式实现)
1.定义xml动画 1)在anim文件夹下定义xml文件 解释:这个文件夹下面的文件会被默认为动画文件,如果这个文件不存在,需要自己创建 display_result_anim.xml <?xm ...
- C#截取中英文混合字符串分行显示
private int GetStrByteLength(string str) { return System.Text.Encoding.Default.GetByteCount(str); } ...
- 自定义Base 64加密
一.前言 最近做软件需要一个功能,就是对文件进行加密.本来嘛,加密算法一堆一堆的,但是试了几个成熟的加密算法后发现对文件进行加密需要的时间很长,特别是上G的文件,这样客户是接受不了的.最后没办法了,好 ...
- 18/9/16牛客网提高组Day2
牛客网提高组Day2 T1 方差 第一眼看就知道要打暴力啊,然而并没有想到去化简式子... 可能因为昨晚没睡好,今天上午困死 导致暴力打了一个半小时,还不对... #include <algor ...
- 【hdu 3478】Catch
[Link]:http://acm.hdu.edu.cn/showproblem.php?pid=3478 [Description] 一个人从起点s出发,假设他在时间t在节点x; 则在时间t+1,他 ...