发布时间:2025-12-10 19:39:32 浏览次数:17
SOAP学习之一:Visual C++创建简单的客户端–使用soap toolkit 3.0获取UTC服务器时间一个小例子使用VC++控制台程序获取UTC服务器时间。使用SoapToolkit3.0实现soap客户端通信。
初始接触 XML及SOAP第一天,摸不着头绪,看了很多文章,总结一下几点心得,附一个小例子使用VC++控制台程序获取UTC服务器时间。
看到的资料VC++都是使用soap toolkit来使用SOAP,soap toolkit目前看最高版本应该是3.0,但是微软已经不再对soap toolkit提供技术支持及更新,在微软官网没找到3.0的下载,目前微软官方能z找到的下载的版本为2.0:http://download.microsoft.com/download/xml/soap/2.0/w98nt42kme/EN-US/SoapToolkit20.exe
如果使用3.0,只能从第三方网站下载。安装soap toolkit很简单,但是要记住安装路径,以便在程序中引用。国人的文章多是翻译一篇SOAP Client Using Visual C++,文章大多雷同,但是由于该文章中的测试实现功能为返回雅虎用户的在线信息(The service indicates Yahoo Messenger’s online presence),雅虎已经停服,照着做程序会在调用EndMessage时报错……到处是坑……
有几个注意问题:
由于使用XML,要在程序中使用命名空间:using namespace MSXML2;如果是VC++控制台程序没什么问题,如果编译时,报错:error C2872:“IXMLDOMDocumentPtr”为不明确的符号
发现已经说明了编译器对IXMLDOMXXX不明确,有两个选择:安装包中默认的msxml.h和生成目录下的msxml4.tlh,导致编译器不知道该用哪个。解决方法参考论坛的方法:去掉namespace,显式的限定接口声明.就是用MSXML2::IXMLDOMDocumentPtr docPtr。不使用命名空间using namespace MSXML2。
参考XMLSpy里使用了获取世界时的服务器http://www.nanonull.com,打开网站查看其请求和返回的例程为下图,其中有我们需要的三个要素:SoapAction;Evvelope;Element。
然后才能建立SOAP消息。
具体实现,首先导入库:
#import "msxml4.dll"using namespace MSXML2; #import "C:\Program Files (x86)\Common Files\MSSoap\Binaries\mssoap30.dll" \ exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \ "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")using namespace MSSOAPLib30; 是否还在为Ide开发工具频繁失效而烦恼,来吧关注以下公众号获取最新激活方式。亲测可用!
【正版授权,激活自己账号】:Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】:官方授权 正版激活 自己使用,支持Jetbrains家族下所有IDE…
然后三个主要操作
创建连接对象:
在客户机/服务器模式中任何客户端应用程序需要作的第一件事就是与服务器进行连接。SoapConnector就是被用来实现客户机端、服务器端应用程序连接器的协议,它还充当定义实现其他协议接口的抽象类,也就是说,SOAP不仅仅局限于充当一种特定的协议。我们会发现,它的一些实现还支持MSMQ、MQ Series、SMTP和TCP/IPTransports。
ISoapConnectorPtr connector;Connector.CreateInstance(__uuidof(HttpConnector));
然后,指定Web服务的地址。接下来,我们必须详细描述该Web服务。Web服务是由Property(HttpConnector的一个属性)指定的。在处理这一属性时有件事情需要指定:我们引用的哪个属性以及该属性的值。例如,根据前面图中标红的关键点,建立链接:
Connector->Property["EndPointURL"] ="http://www.nanonull.com:80/TimeService/TimeService.asmx?WSDL"; Connector->Connect(); Connector->Property["SoapAction"] = "http://www.Nanonull.com/TimeService/getServerTime"; Connector->BeginMessage(); 创建消息序列对象并绑定到连接对象:
ISoapSerializerPtr Serializer;Serializer.CreateInstance(_uuidof(SoapSerializer));Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
建立消息:
SOAP请求被封装在了标记中。<Envelope>标记是该SOAP文档的主标记,SOAP消息通常都被封装在<Envelope>元素中,<Envelope>元素包含一个由<Body>标记指定的消息体,该消息体包含着实际的请求。在C++中,有非常合适的方法可以创建这些标记并指定其值。下面的代码说明了如何利用这些方法:
Serializer->StartEnvelope(“soap”,”http://schemas.xmlsoap.org/soap/envelope/”,””);
// 开始SOAP消息中的一个元素,第一个参数描述了名字空间,
// 如果它是空值,就会缺省地使用SOAP-ENV。第二、第三个参数
// 分别描述了URI和编码类型。
Serialzier->startBody(“”);
// 消息中<Body>元素的开始,第一个参数描述了编码风格Uri,其缺省的值为NONE。
Serializer->StartElement(“getServerTime”,”http://www.Nanonull.com/TimeService/”,””,””);
// SOAP消息中<Body>元素的子元素的开始。第一个参数是子元素名字
//第二个参数是URI,第三个参数是编码类型,最后一个参数是元素的名字空间。
Serializer->WriteString(“someParameterValue”)
// 如有必要,使用上句写元素的值
上面以startXXX开头的函数都相应地有以endXXX开头、结束元素的函数。在完成消息后,系统会调用连接的endMessage()方法,真正开始向服务发送消息。
创建读取对象:
ISoapReaderPtr Reader; Reader.CreateInstance(_uuidof(SoapReader));Reader->Load(_variant_t((IUnknown*)Connector->OutputStream));
完整的例子是一个控制台程序,代码如下:
#include "stdafx.h"#import "msxml4.dll"using namespace MSXML2;#import "C:\Program Files (x86)\Common Files\MSSoap\Binaries\mssoap30.dll" \ exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \ "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")using namespace MSSOAPLib30;int _tmain(int argc, _TCHAR* argv[]){CoInitialize(NULL); ISoapSerializerPtr Serializer; ISoapReaderPtr Reader; ISoapConnectorPtr Connector; // Connect to the service. if(FAILED(Connector.CreateInstance(__uuidof(HttpConnector30)))) //创建对象 { printf("failed"); } // Connect to the service Connector->Property["EndPointURL"] ="http://www.nanonull.com:80/TimeService/TimeService.asmx?WSDL"; Connector->Connect(); // Begin message Connector->Property["SoapAction"] = "http://www.Nanonull.com/TimeService/getServerTime"; Connector->BeginMessage(); // Create the SoapSerializer Serializer.CreateInstance(__uuidof(SoapSerializer30)); // Connect the serializer to the input stream of the connector Serializer->Init(_variant_t((IUnknown*)Connector->InputStream)); // Build the SOAP Message Serializer->StartEnvelope("soap","http://schemas.xmlsoap.org/soap/envelope/",""); Serializer->StartBody(""); Serializer->StartElement("getServerTime","http://www.Nanonull.com/TimeService/","",""); Serializer->EndElement(); Serializer->EndBody(); Serializer->EndEnvelope(); // Send the message to the web service Connector->EndMessage(); // Read the response Reader.CreateInstance(__uuidof(SoapReader30)); // Connect the reader to the output stream of the connector Reader->Load(_variant_t((IUnknown*)Connector->OutputStream),""); //加载返回数据 // Display the result printf("Answer: %sn", (const char *)Reader->RpcResult->text); CoUninitialize(); getchar();return 0;} 程序运行后,输出UTC世界时: