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中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

Atom编辑器mac版下载
最流行的的开源编辑器

WebStorm Mac版
好用的JavaScript开发工具

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能