使用VISUAL C++开发SOAP客户端应用

2024-05-10 07:08

本文主要是介绍使用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客户端应用程序。

这篇关于使用VISUAL C++开发SOAP客户端应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/975780

相关文章

Agent开发核心技术解析以及现代Agent架构设计

《Agent开发核心技术解析以及现代Agent架构设计》在人工智能领域,Agent并非一个全新的概念,但在大模型时代,它被赋予了全新的生命力,简单来说,Agent是一个能够自主感知环境、理解任务、制定... 目录一、回归本源:到底什么是Agent?二、核心链路拆解:Agent的"大脑"与"四肢"1. 规划模

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Linux内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位

Springboot3 ResponseEntity 完全使用案例

《Springboot3ResponseEntity完全使用案例》ResponseEntity是SpringBoot中控制HTTP响应的核心工具——它能让你精准定义响应状态码、响应头、响应体,相比... 目录Spring Boot 3 ResponseEntity 完全使用教程前置准备1. 项目基础依赖(M