HTTP請求式做過Socket程式設計的人都知道,當我們設計一個通訊協定時,「訊息標頭/訊息體」的分割方式是很常用的,訊息頭告訴對方這個訊息是乾什麼的,訊息體告訴對方怎麼幹。
基於HTTP協定實現RPC與基於TCP協定實現RPC比較:
基於HTTP協定的系統間的RPC,具有靈活、實現便利(多種開源的web伺服器支援)、開放(國際標準)且天生支援異質平台之間的呼叫等多個優點,都得到了廣泛的使用。與之相對應的是TCP協定的實現版本,它效率更高,但實現起來更加複雜,且由於協定和標準的不同,難以進行跨平台和企業間的便捷通訊。
HTTP協定實現有其劣勢的一面,由於是上層協議,發送包含同等內容的信息,使用HTTP協議傳輸所佔用的字節數肯定要比使用TCP協議傳輸所佔用的字節數更多。因此,在同等網路環境下,透過HTTP協定傳輸相同內容,效率會比TCP協定的資料傳輸低,訊息傳輸所佔用的時間也更長。當然,透過優化程式碼實現和使用gzip資料壓縮,能夠縮小這一差距。透過權衡利弊,結合實際環境中其效能對於使用者體驗的影響來看,基於HTTP協定的RPC還是有很大的優勢。
1.基於TCP協定實作RPC
服務介面:
public interface SayHelloService{ public String sayHello(String helloArg); }
服務實作:
public class SayHelloServiceImpl implements SayHelloService { @Override public String sayHello(String helloArg) { if(helloArg.equals("Hello")) { return "hello"; }else{ return "bye bye"; } } }
服務消費者Consumer關鍵程式碼:
// 接口名称 String interfacename = SayHelloService.class.getName(); // 需要远程执行的方法 Method method = SayHelloService.class.getMethod("sayHello", java.lang.String.class); // 需要传递到远端的参数 Object[] arguments = {"hello"}; Socket socket = new Socket("127.0.0.1", 1234); // 将方法名称和参数传递到远端 ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeUTF(interfacename); // 接口名称 output.writeUTF(method.getName()); // 方法名称 output.writeObject(method.getParameterTypes()); output.writeObject(arguments); // 从远端读取方法的执行结果 ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); Object result = input.readObject();
服務提供者Privider關鍵代碼:
ServiceSocket server = new ServerSocket(1234); while(true){ Socket socket = server.accept(); //读取服务信息 ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); String interfacename = input.readUTF(); //接口名称 String methodName = input.readUTF(); // 方法名称 Class<?>[] parameterTypes = (Class<?>[])input.readObject(); //参数类型 Object[] arguments = (Object[]) input.readObject(); //参数对象 // 执行调用 Class serviceinterfaceclass = Class.forName(interfacename); Object service = service.get(interfacename); Method method = serviceinterfaceclass.getMethod(methodName, parameterTypes); Object result = method.invoke(service, arguments); ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(result); }
2. 基於HTTP協定的RPC
協定請求定義:
public class Request{ /** * 协议编码 */ private byte encode; /** * 命令 */ private String command; /** * 命令长度 */ private int commandLength; }
協定回應的定義:
public class Response { /** * 编码 */ private byte encode; /** * 响应长度 */ private int responseLength; /** * 响应 */ private String response; }
客戶端實作關鍵程式碼:
// 请求 Request request = new Request(); request.setCommand("HELLO"); request.setCommandLength(request.getCommand().length()); request.setEncode(Encode.UTF8.getValue()); Socket client = new Socket("127.0.0.1", 4567); OutputStream output = client.getOutputStream(); // 发送请求 ProtocolUtil.writeRequest(output, request); InputStream input = client.getInputStream(); Response = response = ProtocolUtil.readResponse(input);
服務端實作關鍵程式碼:
ServerSocket server = new ServerSocket(4567); while(true){ Socket client = server.accept(); //读取响应数据 InputStream input = client.getInputStream(); Request request = ProtocolUtil.readRequest(input); OutputStream output = client.getOutputStream(); // 组装响应 Response response = new Response(); response.setEncode(Encode.UTF8.getValue()); if(request.getCommand().equals("HELLO")){ response.setResponse("hello!"); }else { response.setResponse("bye bye"); } resposne.setResponseLength(response.getResponse().length()); ProtocolUtil.writeResponse(output, response); }
ProtocolUtil 程式碼
public class ProtocolUtil { public static Request readRequest(InputStream input) throws IOException { //读取编码 byte[] encodeByte = new byte[1]; input.read(encodeByte); byte encode = encodeByte[0]; //读取命令长度 byte[] commandLengthBytes = new byte[4]; input.read(commandLengthBytes); int commandLength = ByteUtil.bytes2Int(commandLengthBytes); //读取命令 byte[] commandBytes = new byte[commandLength]; input.read(commandBytes); String command = ""; if(Encode.GBK.getValue() == encode){ command = new String(commandBytes, "GBK"); }else{ command = new String(commandBytes, "UTF8"); } // 组装请求返回 Request request = new Request(); request.setCommand(command); request.setEncode(encode); request.setCommandLength(commandLength); return request; } public static void writeResponse(OutputStream output, Response response) throws IOExceptiono{ //将response响应返回给客户端 output.write(response.getEncode()); // output.write(response.getResponseLength()); //直接write一个int类型会截取低8位传输,丢失高8位 output.write(ByteUtil.int2ByteArray(response.getResponseLength())); if(Encode.GBK.getValue() == resposne.getEncode()){ output.write(response.getResponse().getBytes("GBK")); }else{ output.write(response.getResponse().getBytes("UTF8")); } output.flush(); } }
public static int bytes2Int(byte[] bytes){ int num = bytes[3] & 0xFF; num |= ((bytes[2] << 8) & 0xFF00; num |= ((bytes[1] << 16) & 0xFF0000; num |= ((bytes[0] << 24) & oxFF000000; return num; }
相關推薦:
http://windows.php.net/ 和 http://php.net/ 都提供PHP下載,到底什麼差別呢?
以上是如何在遠端過程中呼叫(RPC)的詳細內容。更多資訊請關注PHP中文網其他相關文章!