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 "你好";
}
}