RPC协议简单实现

RPC协议:像调用本地服务一样调用远程服务,可以做进程间通讯和远程控制

代码实现:

public class Client {
    public static void main(String a[]) throws NoSuchMethodException, IOException, ClassNotFoundException {
        //获得在服务端要启动的服务接口全名
        String name = Say.class.getName();
        //获取在服务端要启动的服务的某个方法
        Method say = Say.class.getMethod("say", String.class);
        //发送给服务端的消息
        Object[] datas = {"你好,Server"};
        //用socket访问远程的8899端口(这里访问的是本地,端口要和Server开放的端口一直)
        Socket socket = new Socket("localhost", 8899);
        //从Socket中获取输出流
        ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
        //将远程服务接口全名写入
        outputStream.writeUTF(name);
        //将服务接口中要调用的方法名写入
        outputStream.writeUTF(say.getName());
        //将参数类型写入
        outputStream.writeObject(say.getParameterTypes());
        //将要传递的数据写入
        outputStream.writeObject(datas);

        //从Socket中获得输入流
        ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
        //读取服务端返回的数据
        Object o = inputStream.readObject();
        //输出
        System.out.println("-----服务器返回:" + o.toString());
    }
}
public class Server {
    /**
     * 也可以用线程池的方式来存每个客户端连接
     * @param a
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void main(String a[]) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //使用map存储接口名和对应的实现类(接口名要与客户端传来的接口名匹配从而找到对应的接口实现类),
        Map<String,Object> hashMap = new HashMap<String,Object>();
        //存储
        hashMap.put(Say.class.getName(),  new SayImpl());

        //启动一个ServerSocket,监听8899端口
        ServerSocket socket = new ServerSocket(8899);
        //死循环不断接收来自客户端的socket连接
        while (true) {
            //在此等待客户端的连接
            Socket accept = socket.accept();
            //获取输入流,从流中拿到客户端传来的接口全名、方法全名、参数类型、参数
            //注意:接口全名包含包名,例:com.xx.abc.a 所以要保证客户端的传来包名与要请求的服务的包名一致,不然无法从map中找到对应接口的实现类
            //服务端获取参数顺序与客户端的参数传递顺序保持一致
            ObjectInputStream inputStream = new ObjectInputStream(accept.getInputStream());
            String name = inputStream.readUTF();
            String methodName = inputStream.readUTF();
            Class<?>[] parameter = (Class<?>[]) inputStream.readObject();
            Object[] datas = (Object[]) inputStream.readObject();

            //通过反射实例化接口
            Class aClass = Class.forName(name);
            //通过全接口名,找到该实现类
            Object say = hashMap.get(name);
            //通过接口对象的getMethod方法传递方法名和参数类型,拿到该接口的指定方法对象
            Method method = aClass.getMethod(methodName, parameter);
            //通过invoke方法执行指定方法
            Object result = method.invoke(say, datas);

            //给客户端发挥数据
            ObjectOutputStream outputStream = new ObjectOutputStream(accept.getOutputStream());
            outputStream.writeObject(result);
        }
    }
}
public interface Say {
    String say(String name);
}
public class SayImpl implements Say {
    public SayImpl() {
    }

    public String say(String name) {
        System.out.println(name);
        return "你好";
    }
}

 

posted @ 2018-03-07 10:27  猴子1  阅读(302)  评论(0编辑  收藏  举报