zoukankan      html  css  js  c++  java
  • C++,C#,JAVA之间webservice互操作问题探讨

    c++用的是gsoap,关于使用gsoap创建webservice的客户端服务端问题,可以参见我以前的随笔: << gsoap使用心得>>
    JAVA用的是axis,用axis创建webservice的客户端和服务端的问题,可以google一番,很多这方面的介绍。
    C#用的是system.webserive这个类库。

    我们的目标是要求这三者之间的webservice互相通讯正常,即能收到客户端发过来的一串字符串,服务器 端返回给客户端一段字符串。
    要保证互相通讯正常,则必须首先明确webservice的采用的SOAP协议。
    根据网上的资料:

    style属性可分为rpc document,rpc document之间的区别为:

        * RPC 样式

    RPC样式指定 元素包含一个将被调用的web方法的名称的元素(wrapper element(封装元素))。这个元素依次为该方法的每个参数还有返回值作了记录。

        * Document 样式

    如果是document 样式,就没有像在RPC样式中的wrapper元素。转而代之的是消息片断直接出现在< SPAN>> 元素之下。没有任何SOAP格式化规则规定元素下能包含什么;它包含的是一个发送者和接收者都达成一致的XML文档。


    ‘Use’ 属性。这与各种类型如何在XML中显示有关,它指定使用某种编码规则对消息片段进行编码,还是使用消息的具体架构来定义片段。如下就是提供的两种选择:

        * encoded

    如果use的值是”encoded”, 则每个消息片段将使用类型属性来引用抽象类型。通过应用由 encodingStyle 属性所指定的编码样式,可使用这些抽象类型生成具体的消息。最常用到的SOAP编码样式是在SOAP1.1中定义的一组序列化规则,它说明了对象、结构、数组和图形对象应该如何序列化。通常,在应用程序中使用SOAP编码着重于远程进程调用和以后适合使用RPC消息样式。

        * Literal

    如果use 的值是”Literal”, 则每个片段使用 element 属性(对于简单片段)或 type 属性(对于复合片段)来引用具体架构,例如,数据根据指定的架构来序列化,这架构通常使用W3C XML架构来表述。

    我找了很多这方面的资料,但是具体理解起来还是很困难。单从字面取理解其实很简单,但是联系到实际操作中,根据各种方式生成的wsdl来看,却很难理解其中的异同。因为遵循document格式的soap消息看上去很像rpc格式。而且对于简单对象如int string等类型来说,好像并未有十分明显的异同,因此在我测试过程中,一直都是比较模糊的。我也采用了comview,iris抓包工具,抓获它们之间发送的数据包,对问题分析还是有所帮助的。

    我是以gsoap为主线进行测试的,因此在测试完成后,对自己的测试结果持有怀疑,我感觉是自己对gsoap的rpc docment encoded literal之间的差异并没有理解透彻,我是这么定义的:
    document/literal方式:
    //gsoap ns service name: EASReceive
    //gsoap ns service location:
    http://services.xmethods.net/soap
    //gsoap ns service namespace:
    http://tempuri.org/
    //gsoap ns service style: document
    //gsoap ns service encoding: literal
    //gsoap ns service method-action: EASReceive ""

    typedef char *xsd__string;
    int ns__EASReceive(xsd__string strSubmitData ,xsd__string *strPxFormData);  

    rpc/encoded方式:
    //"OAMethod.h"的内容:
    //gsoap ns service name: EASReceive
    //gsoap ns service location:
    http://services.xmethods.net/soap
    //gsoap ns service namespace:
    http://tempuri.org/
    //gsoap ns service style: rpc
    //gsoap ns service encoding: encoded  
    //gsoap ns service method-action: EASReceive ""


    int ns__EASReceive(char* strSubmitData ,char** strPxFormData);  

    可我发现生成的wsdl中除了style use属性值不一样外,并没有其它什么区别,对了在encoded中我还加了soap2cpp.exe -e选项(加与不加都测试过)。


    C#的客户端多种方式都测试过,经测试只有采用
        [System.Web.Services.Protocols.SoapRpcMethodAttribute(
            "http://tempuri.org/EASReceive",
            RequestNamespace = "http://tempuri.org/",
            Resp,
            Use = System.Web.Services.Description.SoapBindingUse.Literal)]

        [System.Web.Services.Protocols.SoapRpcMethodAttribute(
            "http://tempuri.org/EASReceive",
            RequestNamespace = "http://tempuri.org/",
            Resp,
            Use = System.Web.Services.Description.SoapBindingUse.encoded)]
    可以调通。

    C#的服务端却只有一种方式可以调通:
            [WebMethod]
            [SoapRpcMethod(
                Action = "http://tempuri.org/EASReceive",
                RequestNamespace = "http://tempuri.org/",
                Resp,
                Use = System.Web.Services.Description.SoapBindingUse.Literal)] //encoded不行
            [return: XmlElement("strPxFormData", IsNullable = false)]

    也用C#的wsdl自动生成工具测试过,根据gsoap生成的wsdl文件 ,自动生成的代码也不能和gsoap完成通讯正常。我一直理解不明白,按道理说只要将编码方式一致即可通讯,不知是否我c#端代码编写有问题?在网上搜索 C#端的资料时,发现C#端对webservice中自定义xml文件方案是十分灵活的,可以随意定制传输的xml节点,因此其实关键问题还是格式必须保证互相一致,这样在收到soap消息后,双方都可以对xml进行正确的解析。经过反复调试,最终还是调通了,都采用rpc/literal方式即可。 JAVA端和gsoap通讯倒是没有问题,采用何种编码只要统一即可通讯,因此基于测试发现的C#的"局限性",我们统一成rpc/literal。



    JAVA客户端代码:
      String endpoint = "http://192.168.8.94/csharp_demo/Service1.asmx";
      Service     service   =   new   Service();
      Call           call         =   (Call)   service.createCall();
      call.setTargetEndpointAddress(   new   java.net.URL(endpoint)   );
      call.setUseSOAPAction(true);

      String soapActi;  
      call.setSOAPActionURI(soapActionURI);  
      
      
      call.setOperationStyle(org.apache.axis.constants.Style.RPC);
      call.setOperationUse(org.apache.axis.constants.Use.LITERAL);
      
      String strSubmitData = new String("yes or no!???");
      call.setOperationName(new QName("http://tempuri.org/","EASReceive"));
      call.addParameter("strSubmitData",org.apache.axis.encoding.XMLType.XSD_STRING,javax.xml.rpc.ParameterMode.IN);
      //call.addParameter(new QName("http://tempuri.org/","strSubmitData"), org.apache.axis.encoding.XMLType.XSD_STRING, javax.xml.rpc.ParameterMode.IN);
      
      call.setReturnType(   XMLType.XSD_STRING  );
      
      //oper.setElementQName(new QName("http://tempuri.org/","EASReceive"));
      //call.setOperation(oper);  
      String   ret   =   (String) call.invoke(   new   Object[]   { strSubmitData} );
      System.out.println("Get   result   :   "   +   ret);

    JAVA服务端代码:略

    最后,欢迎大家一起探讨,感觉问题还是很多,现在虽然保证了通讯正常,但实际上我头脑还是浆糊着呢,呵呵!
    令关于C#端必须要求soapAction的问题,有两种解决方案:
    1、C#服务端加入以下代码,但测试发现,部署到IIS后,并不起作用,具体原因不知道。
    [SoapRpcService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]  //设置无需指派soapAction 但部署到iis 上时并未起作用
    //[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]
    2、在客户端加上soapAction,gsoap客户端传入soapAction即可。

    还有一个棘手的问题,就是中文乱码问题,呵,说棘手是因为如果不清楚的确很棘手,其实解决起来也很简单,就是保证通讯编码一致。这里的通讯编码一致有两层意思:
    1、webservice间传输编码,都保证为UTF8,gsoap加入soap_set_mode(s.soap, SOAP_C_UTFSTRING)即可。java,c#端都是默认以utf8传输的。
    2、传输前参数的字符编码,

  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/cy163/p/1557853.html
Copyright © 2011-2022 走看看