zoukankan      html  css  js  c++  java
  • 用VisualC++建立SOAP客户端应用(一)

    用VisualC++建立SOAP客户端应用(一)

    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将它输出到屏幕上。

    用VisualC++建立SOAP客户端应用(二)

    一、先决条件:
    必须熟悉使用COM,特别要熟悉COM中的Smart Pointers。我通过导入方法将COM接口转换成Smart Pointers。系统必须安装了Microsoft SOAP Toolkit和Microsoft XML Parser。文末参考一节介绍如何下载工具箱。文末附件可下载本文源程序。

    二、SOAP编程基础:
    下面开始介绍一个简单SOAP应用中所包含的类。在此之前,必需先导入所需的类型库,然后程序才能够使用SOAP的类。

    导入类型库:
    SOAP中使用的对象和接口都在mssoap1.dll文件中。这个文件在安装Microsoft SOAP Toolkit 2.0时生成,存在路径:"C:/Program Files/Common Files/MSSoap/Binaries/MSSOAP1.dll"。用#import将该文件导入到程序中。类型库的内容在导入时被转换成COM smart pointers来描述COM接口。因为SOAP完全依赖于XML,因此必需用Microsoft XML Parser来处理XML。Microsoft XML parser在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客户端应用有以下三步骤:
    1- 指定和连接Web服务器。
    2- 准备和发送消息。
    3- 读取服务端返回的信息。

    下面是在基本SOAP客户端要使用到的类:

    1- SoapConnector:
    在客户/服务模式下,首先要做的事就是连接服务器。SoapConnector 类执行客户端与服务端之间的消息传送协议。 SoapConnector是一个抽象类,定义了协议执行的接口。事实上, SoapConnector类不定义执行某种特定的传送协议,例如:MSMQ, MQ Series, SMTP 和 TCP/IP等。为简便起见,本文只说明使用HTTP传送协议,它是由Microsoft SOAP Toolkit 2.0中的HttpConnector 类来执行的。

    SoapConnector类使用步骤如下:
    a) 创建SoapConnector类对象:
     ISoapConnectorPtr connector;
     Connector.CreateInstance(__uuidof(HttpConnector));

    b) 指定Web服务器地址:
    指定服务器,要做二件事:选择HttpConnector的属性和相应的属性值。本文示例选用EndPointURL属性:
     Connector->Property ["EndPointURL"] = "some url pointing to web service";

    以下是属性选项说明(属性名是大小写敏感的):
    AuthPassword:客户口令
    AuthUser:客户名
    EndPointURL :客户URL
    ProxyPassword:  代理(proxy)口令
    ProxyPort :代理断口
    ProxyServer :代理服务器的IP地址或主机名
    ProxyUser :代理用户名
    SoapAction:HTTP的抬头值。这个属性只使用于低级API。它将忽略SoapClient接口(高级API)中的ConnectorProperty属性 。
    SSLClientCertificateName:指定使用Secure Sockets Layer (SSL)加密协议。语法如下:
     [CURRENT_USER | LOCAL_MACHINE/[store-name/]]cert-name with the defaults being CURRENT_USER/MY (与Microsoft Internet Explorer用法相同)。
    Timeout:HttpConnector的超时限制,以毫秒为单位。
    UseProxy:定义是否使用代理(proxy)。缺省值为False。如果将这个属性为真(True),又没有设置上面的ProxyServer值,代理服务器将使用IE里的代理服务器。此时HttpConnector将不理会IE的"Bypass Proxy"(绕道)设置。
    UseSSL:定义是否使用SSL(True 或 False)。此值设置为真时,HttpConnector对象不管WSDL设置是HTTP或HTTPS都用SSL连接方式。若此值设置为非真, HttpConnector对象只在WSDL设置为HTTPS时才用SSL方式连接。
     
    c) 与Web服务器连接:
     Connector->Connect();

    d) 指定动作:
    Connector->Property ["SoapAction"] = "some uri";

    e) 启动消息句柄:
    必需在SoapSerializer(消息准备函数)之前先启动消息处理机制
    Connector->BeginMessage();

    在消息处理完毕之后,用EndMessage()函数将消息送往服务器。
    .
    .
    [ 消息准备代码 ]
    .
    .
    Connector->EndMessage();

    以上就是与服务器连接的过程。下面介绍如何创建和准备消息。

    SoapSerializer:
    用于建立送往服务器的SOAP消息。在与服务器通讯之前,SoapSerializer对象必需先与SoapConnector对象连接。SoapSerializer的初始化函数将建立这个内部连接。初始化代入的参数是InputStream (数据流):
    // 创建SoapSerializer对象,并用InputSTream进行初始化。
     ISoapSerializerPtr Serializer;
     Serializer.CreateInstance(_uuidof(SoapSerializer));
     Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));

    下面是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)里。信封里的<Body>标记中安放信息体,其中包含具体请求。在C++里,用相应的方法来解释这些标记并定义有关的值。
    下面的代码说明如何使用这些方法:


    Serializer->startEnvelope("SOAP","","");
    // 开始处理SOAP消息。第一个参数是命名空间,缺省为SOAP-ENV。
    // 第二个参数定义URI。第三个参数定义Serialzier->startBody("")函数的编码方式。
    // 开始处理<Body>元素,第一个参数是URI的编码类型,缺省为NONE。

    Serializer->startElement("someMethodName","","","m");
    // 开始处理Body里的子元素。
    // 第一个参数是元素名。第二个参数是URI。
    // 第三个参数编码类型。第四个参数是元素的命名空间。

    Serializer->WriteString("someParameterValue")
    // 写入元素值

    在上面的每个startXXX函数后都要又相应的endXXX函数来结尾。消息做完之后,连接器就调用endMessage()方法将消息发送到服务器。

    至此,我们已经连接了服务器,制作了相应的消息。最后一个步骤就是接收服务器回应。

    SoapReader:
    读取服务器返回的信息,将信息解析之后装入DOM,为进一步处理所用。下面是服务器返回的SOAP回应信息:

    <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接收服务器返回的信息)。

    // 创建SOAPReader对象,并连接到outputstream
     ISoapReaderPtr Reader;
     Reader.CreateInstance(_uuidof(SoapReader));
     Reader->Load(_variant_t((IUnknown*)Connector->OutputStream));
    // load方法还可以用于加载XML文件或字符串

    将回应信息加载到SoapReader对象之后,就可以用它的RPCResult属性来获取结果。不过,But RPCResult并不直接返回结果,它返回<Body>的第一个实体元素,然后用text属性读取该元素属性值:
    Reader->RPCResult->text

    三、举例说明一个简单的SOAP客户端应用:
    本文示例用www.xmethods.net做服务器。这个服务器指向Yahoo在线信息。
    可以在http://www.xmethods.net/ve2/ViewListing.po?serviceid=156找到有关细节。
    下面的代码中要输入一个参数,即Yahoo的用户ID。返回结果为0表示离线,1表示在线。
    其他细节可参阅:http://www.allesta.net:51110/webservices/wsdl/YahooUserPingService.xml

    四、参考:
    The SOAP specification Simple Object Access Protocol (SOAP) 1.1 - W3C Note :
    http://www.w3.org/TR/SOAP
    Microsoft SOAP Toolkit Download :
    http://download.microsoft.com/download/xml/soap/2.0/w98nt42kme/EN-US/SoapToolkit20.exe

    五:本文示例的SOAP代码:
    #include <stdio.h>

    #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;

       // 连接服务器
       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->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();

       // 向服务器发送信息
       Connector->EndMessage();

       // 读取回应
       Reader.CreateInstance(__uuidof(SoapReader));

       // 连接输出流
       Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");

       // 显示结果
       printf("Answer: %s/n", (const char *)Reader->RPCResult->text);
         CoUninitialize();
    }
     

  • 相关阅读:
    OSI,TCP/IP,五层协议的体系结构,以及各层协议
    linux及安全期中总结——20135227黄晓妍
    linux及安全《Linux内核设计与实现》第四章——20135227黄晓妍
    linux及安全《Linux内核设计与实现》第三章——20135227黄晓妍
    linux及安全第八周总结——20135227黄晓妍
    linux及安全第七周总结——20135227黄晓妍
    linux及安全第六周总结——20135227黄晓妍
    linux及安全第五周总结——20135227黄晓妍
    linux及安全第四周总结——20135227黄晓妍
    linux及安全《Linux内核设计与实现》第二章——20135227黄晓妍
  • 原文地址:https://www.cnblogs.com/wqj1212/p/4174875.html
Copyright © 2011-2022 走看看