<5> webservice 客户端-服务器通信数据流图

一、 SOAP协议的实现原理
用soap实现远程调用,就是在相同或不同平台之间完成客户端和服务器端的通信。即客户端发送soap请求,服务器端接受请求,分析其中包含的信息,调用相应的函数并将返回值封装成soap消息发送给客户端,最后客户端解析应答消息。归根到底就是通过http在http请求的body部分发送soap协议封装的xml信息,所以本质上也可以直接通过socket或httpclient来发送soap请求到webservice服务地址。比如:
   
//建立与WebService服务端的连接
    Socket sock = new Socket("192.168.2.6", 8080);
    
    //建立向WebService服务端的输出流,编码格式为UTF-8
    BufferedWriter  wr = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
    
    //参照用Ethereal截获的信息一样向输出流写入数据
    //path就是webservice服务的相对地址
    wr.write("POST "+path+" HTTP/1.0\r\n");
    wr.write("Host: "+host+"\r\n");
    wr.write("Content-Length: 593\r\n");
    wr.write("Content-Type: text/xml; charset=\"UTF-8\"\r\n");
    wr.write("SOAPAction: \"\"\r\n");
    wr.write("Accept: */*\r\n");
    wr.write("Cache-Control: no-cache\r\n");
    wr.write("Pragma: no-cache\r\n");
    wr.write("\r\n");
    wr.write(xmldata);
    wr.flush();
        ...
    wr.flush();
    
    //建立来自WebService服务端的输入流
    BufferedReader rd = new BufferedReader(new 
InputStreamReader(sock.getInputStream()));
    String line;
    StringBuffer xmlReturn=new StringBuffer();
    
    //循环读入从服务端发送回来的数据
    while((line = rd.readLine()) != null) 
    {
        xmlReturn.append(line);
    }

    sock.close();


按照上面这个思路,我们可以直接使用Socket实现WebService客户端,同样可以调用标准的WebService服务端。唯一的 缺点就是,我们需要对WebService返回的信息进行 解析。由于WebService返回的内容是XML格式的。所以我们可以使用DOM或SAX对XML进行解析。只是还是稍显麻烦。不过即便如此,我们用Socket直接调用WebService,这已经很大程度上解决了如果编写一个通用WebService客户端的问题。所以用这种方式编写的客户端,不仅可以调用不同Java WebService框架发布的WebService,甚至也可以调用不同语言开发平台上发布的WebService。
注意,实际使用中是很少这样做的,已经有很多框架支持自动生成客户端和服务端代码,可以像普通api一样调用webservice方法。

1.1 体系结构
用户程序可以通过soap实现远程调用,首先用户程序向一个名为SoapClient的对象发送消息请求服务器上某一名为operation的操作,SoapClient处理该消息后向服务器发出soap请求。在服务器端,由一个名为SoapServer的对象接受请求调用相应的组件方法执行相应的操作。SoapServer获得操作结果后将其以soap应答的形式返回给客户端。最后,客户端的SoapClient处理处理SOAP应答并将结果封装在消息中发送给用户程序。这样,通过SoapClient和SoapServer的桥梁作用,客户端便可以调用本地函数一样调用服务端的函数。客户端和服务器端通信的数据流图如下图:


在实际应用中,当使用SoapClient和SoapServer进行SOAP的请求应答时,客户端和服务器端都必须先通过一个名为javax.wsdl.xml.WSDLReader(在wsdl4j-version.jar中)的对象来获取WSDL文件中的Soap消息结构,以此保证通信的一致性。下面分别描述客户端和服务端的具体实现情况。

1.2 客户端
SoapClient在接受用户程序的远程服务请求后,一方面,通过WSDLReader从服务器上获取wsdl文件,为相应的服务操作产生一个名为WSDLOperation的对象,WSDLOperation调用名为GetOperationParts的方法,获得操作的输入输出消息格式,另一方面,SoapClient为服务操作的每个参数产生一个名为SoapMapper的对象,并调入各对象操作所需的参数值。一个名为SoapSerializer的对象从相应的SoapMapper中建立SOAP请求消息并通过一个名为SoapConnecter的对象发送给服务器,同时侦听服务器的应答。当服务器处理SOAP请求并将SOAP应答返回给客户端后,SoapReader将结果赋值给相应的SoapMapper,同时也将结果返回给用户程序,详细的数据流图如下图:


1.3 服务器端
当服务器端的SoapServer接收到客户端的Soap请求后,一方面,SoapReader将请求消息存放到一个DOM结构中,WSDLReader将wsdl文件存放到另一个DOM结构中,然后分析该请求并为其产生一个WSDLOperation对象,WSDLOperation调用GetOperationParts方法,获得操作的输入输出消息格式;另一方面,SoapServer为服务操作的每个参数产生SoapMapper对象,并调入各对象操作所需的参数值。SoapServer调用与该操作响应的组件方法后,将返回结果映射到相应的SoapMapper对象中,并用SoapSerializer将返回值封装在Soap应答消息中并发送到客户端,详细的数据流图如下:


1.4 其他
从上面客户端和服务端的调用过程,我们看到webservice的调用中存在着序列化和反序列化的过程,也就是按照一定的编码格式(soap协议本身就有内置的类型转换规范: http://schemas.xmlsoap.org/soap/encoding/),把对象映射为xml或根据xml把对象映射为对象,因此webservice调用中的传递的参数也都必须可序列化。
参考:
http://www.ibm.com/developerworks/cn/webservices/ws-soapmap/part1/index.html
http://www.ibm.com/developerworks/cn/webservices/ws-soapmap/part2/index.html

了解jax-rpc和jax-ws的区别还可以参考:
http://www.ibm.com/developerworks/cn/webservices/ws-tip-jaxwsrpc.html

参考:
《SOAP的原理及实现》  杭州电子工业学院学报

猜你喜欢

转载自zoroeye.iteye.com/blog/2069245