RPC的全稱是Remote Procedure call,是進程間通訊方式。java
他容許程序調用另外一個地址空間的過程或者函數,不用去關注此過程或函數的實現細節。好比兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數或者方法,因爲不在一個內存空間,不能直接調用,這時候須要經過就能夠應用RPC框架的實現來解決。web
RPC有不少開源的框架實現這裏主要介紹java自帶的RMI編程
RMI全稱是Remote Method Invocation-遠程方法調用,Java RMI在JDK1.1中實現的,其威力就體如今它強大的開發分佈式網絡應用的能力上,是純Java的網絡分佈式應用系統的核心解決方案之一。其實它能夠被看做是RPC的Java版本。要求客戶端和服務端都要用java實現服務器
(1)服務端代碼實現:網絡
IHello類實現:數據結構
import java.rmi.Remote; import java.rmi.RemoteException; public interface IHello extends Remote{ /** * 簡單的返回「Hello World!"字樣 * @return 返回「Hello World!"字樣 * @throws java.rmi.RemoteException */ public String helloWorld() throws RemoteException; /** * 一個簡單的業務方法,根據傳入的人名返回相應的問候語 * @param someBodyName 人名 * @return 返回相應的問候語 * @throws java.rmi.RemoteException */ public String sayHelloToSomeBody(String someBodyName) throws RemoteException; }
HelloImpl實現IHello實現:框架
import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class HelloImpl extends UnicastRemoteObject implements IHello{ protected HelloImpl() throws RemoteException { super(); } @Override public String helloWorld() throws RemoteException { return "Hello Word"; } @Override public String sayHelloToSomeBody(String someBodyName) throws RemoteException { return "你好," + someBodyName + "!"; } }
HelloServer:編程語言
import java.net.MalformedURLException; import java.nio.channels.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; /** * Created by IntelliJ IDEA. * Date: 2008-8-7 22:03:35 * 建立RMI註冊表,啓動RMI服務,並將遠程對象註冊到RMI註冊表中。 */ public class HelloServer { public static void main(String args[]) throws java.rmi.AlreadyBoundException { try { //建立一個遠程對象 IHello rhello = new HelloImpl(); //本地主機上的遠程對象註冊表Registry的實例,並指定端口爲8888,這一步必不可少(Java默認端口是1099),必不可缺的一步,缺乏註冊表建立,則沒法綁定對象到遠程註冊表上 LocateRegistry.createRegistry(8888); //把遠程對象註冊到RMI註冊服務器上,並命名爲RHello //綁定的URL標準格式爲:rmi://host:port/name(其中協議名能夠省略,下面兩種寫法都是正確的) Naming.bind("rmi://localhost:8888/RHello",rhello); // Naming.bind("//localhost:8888/RHello",rhello); System.out.println(">>>>>INFO:遠程IHello對象綁定成功!"); } catch (RemoteException e) { System.out.println("建立遠程對象發生異常!"); e.printStackTrace(); } catch (AlreadyBoundException e) { System.out.println("發生重複綁定對象異常!"); e.printStackTrace(); } catch (MalformedURLException e) { System.out.println("發生URL畸形異常!"); e.printStackTrace(); } } }
(2)客戶端代碼實現:分佈式
新建客戶端工程GiveMeWords,客戶端須要將服務端的IHello接口拷貝過來,而且必須和服務器端包名相同。不然會報以下錯誤(本人親測):ide
java.lang.ClassNotFoundException: test.rmi.IHello (no security manager: RMI class loader)
import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; public class HelloClient { public static void main(String args[]){ try { //在RMI服務註冊表中查找名稱爲RHello的對象,並調用其上的方法 IHello rhello =(IHello) Naming.lookup("rmi://localhost:8888/RHello"); System.out.println(rhello.helloWorld()); System.out.println(rhello.sayHelloToSomeBody("熔岩")); } catch (NotBoundException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } }
服務端工程結構截圖
客戶端工程結構截圖
先運行服務器端代碼,在運行客戶端代碼。運行結果:
一、WebService是一種跨編程語言和跨操做系統平臺的遠程調用技術。
XML+XSD,SOAP和WSDL就是構成WebService平臺的三大技術。Web Service採用http協議傳輸,數據格式爲特定格式的XML。
SOAP協議=HTTP協議+XML協議
WSDL(Web Service Description Language)基於XML語音的,用於描述Web Service及其函數、參數和返回值。它是WebService客戶端和服務器端都能理解的標準格式。WSDL文件保存在Web服務器上,經過一個url地址就能夠訪問到它。客戶端要調用一個WebService服務以前,要知道該服務的WSDL文件的地址。WebService服務提供商能夠經過兩種方式來暴露它的WSDL文件地址:1.註冊到UDDI服務器,以便被人查找;2.直接告訴給客戶端調用者。也就是說咱們要進行Web Service開發,經過服務器端的WSDL文件,咱們就能夠編寫客戶端調用代碼。
服務端代碼:
import javax.jws.WebService; import javax.xml.ws.Endpoint; @WebService public class Function { public String transWords(String words){ String res = ""; for(char ch : words.toCharArray()){ res += "\t" + ch + "\t"; } return res; } public static void main(String[] args){ Endpoint.publish("http://localhost:9001/Service/Function", new Function()); System.out.println("publish success"); } }
運行成功後訪問http://localhost:9001/Service/Function?wsdl。wsdl文件以下:
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --> <!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --> <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webService.test/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webService.test/" name="FunctionService"> <types> <xsd:schema> <xsd:import namespace="http://webService.test/" schemaLocation="http://localhost:9001/Service/Function?xsd=1"/> </xsd:schema> </types> <message name="transWords"> <part name="parameters" element="tns:transWords"/> </message> <message name="transWordsResponse"> <part name="parameters" element="tns:transWordsResponse"/> </message> <portType name="Function"> <operation name="transWords"> <input wsam:Action="http://webService.test/Function/transWordsRequest" message="tns:transWords"/> <output wsam:Action="http://webService.test/Function/transWordsResponse" message="tns:transWordsResponse"/> </operation> </portType> <binding name="FunctionPortBinding" type="tns:Function"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <operation name="transWords"> <soap:operation soapAction=""/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="FunctionService"> <port name="FunctionPort" binding="tns:FunctionPortBinding"> <soap:address location="http://localhost:9001/Service/Function"/> </port> </service> </definitions>
WSDL 文檔在Web服務的定義中使用下列元素:
而後在客戶端項目下運行以下命令 wsimport -s Documents/workspace/GiveMeWords/src -p com.shu.service -keep http://localhost:9001/Service/Function?wsdl 便可自動生成客戶端代碼
Documents/workspace/GiveMeWords/src代碼位置
com.shu.service包名
測試代碼:
public class Test { /** * 測試webservice此做爲客戶端 * test項目中的webService包下面的Function做爲服務端 *wsimport -s Documents/workspace/GiveMeWords/src -p com.shu.service -keep http://localhost:9001/Service/Function?wsdl * @param args */ public static void main(String[] args){ Function fu = new FunctionService().getFunctionPort(); String str = fu.transWords("get my words"); System.out.println(str); } }
運行便可調用服務端的遠程方法transWords()方法。可是客戶端怎麼知道服務端暴露出來的服務就是transWords呢,還有參數返回值這些客戶端是怎麼知道的?咱們回到上面的WSDL文件:
<portType name="Function"> <operation name="transWords"> <input wsam:Action="http://webService.test/Function/transWordsRequest" message="tns:transWords"/> <output wsam:Action="http://webService.test/Function/transWordsResponse" message="tns:transWordsResponse"/> </operation> </portType>
operation表情代表方法暴露服務的方法名是transWords。<input>標籤標示輸入參數,<output>函數返回值。這樣咱們就獲得了咱們想要的接口了。總之經過WSDL文件咱們就能夠進行編程。