RPCプロトコル

10172 ワード

一、RPC協議とは何ですか?
RPC,   Remote Procedure Call,       ,           。
                  。           。
 RMI(      )HessianHttp invoker 。
  ,RPC
二、RPC構造分解
深く浅くRPCを出す
三、RPC簡単判例参考
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHi(String name) {
        return "Hi, " + name;
    }

}
public class ServiceCenter implements Server {
    private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    private static final HashMap serviceRegistry = new HashMap();

    private static boolean isRunning = false;

    private static int port;

    public ServiceCenter(int port) {
        this.port = port;
    }

    public void stop() {
        isRunning = false;
        executor.shutdown();
    }

    public void start() throws IOException {
        ServerSocket server = new ServerSocket();
        server.bind(new InetSocketAddress(port));
        System.out.println("start server");
        try {
            while (true) {
                // 1.      TCP  ,  TCP        task,      
                executor.execute(new ServiceTask(server.accept()));
            }
        } finally {
            server.close();
        }
    }

    public void register(Class serviceInterface, Class impl) {
        serviceRegistry.put(serviceInterface.getName(), impl);
    }

    public boolean isRunning() {
        return isRunning;
    }

    public int getPort() {
        return port;
private static class ServiceTask implements Runnable {
    Socket clent = null;

    public ServiceTask(Socket client) {
        this.clent = client;
    }

    public void run() {
        ObjectInputStream input = null;
        ObjectOutputStream output = null;
        try {
            // 2.                ,         ,      
            input = new ObjectInputStream(clent.getInputStream());
            String serviceName = input.readUTF();
            String methodName = input.readUTF();
            Class>[] parameterTypes = (Class>[]) input.readObject();
            Object[] arguments = (Object[]) input.readObject();
            Class serviceClass = serviceRegistry.get(serviceName);
            if (serviceClass == null) {
                throw new ClassNotFoundException(serviceName + " not found");
            }
            Method method = serviceClass.getMethod(methodName, parameterTypes);
            Object result = method.invoke(serviceClass.newInstance(), arguments);

            // 3.         ,  socket      
            output = new ObjectOutputStream(clent.getOutputStream());
            output.writeObject(result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (clent != null) {
                try {
                    clent.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
public class RPCClient {
    @SuppressWarnings("unchecked")
    public static  T getRemoteProxyObj(final Class> serviceInterface, final InetSocketAddress addr) {
        // 1.           JDK     ,               
        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class>[]{serviceInterface},
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Socket socket = null;
                        ObjectOutputStream output = null;
                        ObjectInputStream input = null;
                        try {
                            // 2.  Socket   ,               
                            socket = new Socket();
                            socket.connect(addr);

                            // 3.             、   、                
                            output = new ObjectOutputStream(socket.getOutputStream());
                            output.writeUTF(serviceInterface.getName());
                            output.writeUTF(method.getName());
                            output.writeObject(method.getParameterTypes());
                            output.writeObject(args);

                            // 4.             ,       
                            input = new ObjectInputStream(socket.getInputStream());
                            return input.readObject();
                        } finally {
                            if (socket != null) socket.close();
                            if (output != null) output.close();
                            if (input != null) input.close();
                        }
                    }
                });
    }
}
public class RPCTest {
    @Test
     public void product() throws IOException{
         Server serviceServer = new ServiceCenter(8088);
         serviceServer.register(HelloService.class, HelloServiceImpl.class);
         serviceServer.start();
     }
     @Test
     public void consume(){
         HelloService service = RPCClient.getRemoteProxyObj(HelloService.class, new InetSocketAddress("localhost", 8088));
         System.out.println(service.sayHi("test"));
     }
}
実例まとめ:ここで実現される簡単なRPCのフレームワークはJava言語を使って開発され、Java言語と高度に結合され、そして通信方式に採用されているSocketはBIOに基づいて実現されたもので、IOの効率は高くない。次のいくつかの方法から改善することが考えられます。
JSON**データ転送**に基づくRPCフレームを採用することができます。BIOの代わりにNettyを使って、NIOを使っても良いです。Hadoop AvroとGoogle protobufなどのオープンソースのプログレッシブメカニズムを使用します。サービス登録はZookeeperで管理できます。アプリケーションをより安定させることができます。