RPC是一种远程过程调用, 它是一种通过网络从远程计算机程序上请求服务, 而不需要了解底层网络技术的协议
RPC可以把远程服务像本地服务一样调用, 以Java
中为例, 客户端与服务端一般共用一个核心包, 核心包中包含了需要调用服务的接口
在服务端实现这些接口, 客户端通过Socket
等方式连接服务端, 发生调用的信息(方法名, 参数等)
服务端接收后执行相应动作, 最后通过网络返回计算结果, 一次RPC调用就完成了
下面是Java
中的简单实现
共用接口
1 2 3
| public interface TestService { String print(String s); }
|
一个简单的打印服务, 不包含实现
客户端
在客户端代码中自始至终没有编写服务的实现, 只有一个接口, 但是又可以得到服务的实例,
要做到这点需要用到Java
中的动态代理Proxy.newProxyInstance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.InetSocketAddress; import java.net.Socket;
public class Consumer { public static void main(String[] as) {
TestService service = (TestService) Proxy.newProxyInstance(TestService.class.getClassLoader(), new Class<?>[]{TestService.class}, (Object proxy, Method method, Object[] args) -> { try(Socket socket = new Socket()){ socket.connect(new InetSocketAddress(12306)); ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream()); os.writeUTF(method.getName()); os.writeObject(method.getParameterTypes()); os.writeObject(args); return new ObjectInputStream(socket.getInputStream()).readObject(); }catch (Exception e){ return null; } }); System.out.println(service.print("abc")); } }
|
通过对象流把参数等信息发送给服务端
服务端
一般服务端是预先实例化服务, 以完整类名为Key
把服务存进集合供调用, 或者依赖现成的Springboot
等框架管理服务, 下面是服务端的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket;
public class Producer {
public static void main(String[] args) {
TestService service = new TestServiceImpl();
try (ServerSocket serverSocket = new ServerSocket()){ serverSocket.bind(new InetSocketAddress(12306));
try(Socket accept = serverSocket.accept()){ ObjectInputStream is = new ObjectInputStream(accept.getInputStream()); String methodName = is.readUTF(); Class<?>[] parameterTypes = (Class<?>[]) is.readObject(); Object[] arguments = (Object[]) is.readObject(); Object result = TestService.class.getMethod(methodName,parameterTypes).invoke(service,arguments); new ObjectOutputStream(accept.getOutputStream()).writeObject(result); } } catch (Exception e) { e.printStackTrace(); }
} }
|
服务实例
服务端编写服务实例代码
1 2 3 4 5 6 7
| public class TestServiceImpl implements TestService{
@Override public String print(String s) { return "**"+s+"**"; } }
|
结果
至此可以看到客户端调用的
1
| System.out.println(service.print("abc"));
|
打印出了
就好像调用了本地服务一样