一
思路:
1.先建立一个service 和其实现类 如下
2.需要创建一个代理服务器类 来完成与客户端的通信
3.代理服务器类 需要调用线程池的execute()方法 来实现业务调用 所以需要些一个线程类ProxyHandler
public class ProxyHandler implements Runnable {
private Socket socket;//客户端套接字
private Object service;//服务,也就是调用方法的对象
public ProxyHandler(Socket socket, Object service) {
this.socket = socket;
this.service = service;
}
@Override
public void run() {
System.out.println("开始执行服务端的处理方法");
ObjectInputStream objectInputStream=null;
ObjectOutputStream objectOutputStream=null;
try {
//先接受客户端发送过来的数据
objectInputStream=new ObjectInputStream(socket.getInputStream());
//反序列化 里面应该包含 请求那个服务(那个接口) 方法名 参数数组
RPCRequest request= (RPCRequest) objectInputStream.readObject();
//通过反射 调用方法
Object result=myInvoke(request);
//把服务端的结果,序列化后传回客户端
objectOutputStream=new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}finally {
if (objectOutputStream!=null){
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 通过反射调用了服务端的方法
* @param request
* @return
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
private Object myInvoke(RPCRequest request) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object[] parameters = request.getParameters();
Class<?>[] types = new Class[parameters.length];
//把参数转化为对应的类对象
for (int i = 0; i <types.length ; i++) {
types[i]=parameters[i].getClass();
}
//getMethod方法 第一个参数就是方法名, 第二个参数就是方法参数对应的类对象 如String.class
Method method=service.getClass().getMethod(request.getMethodName(),types);
//invoke()方法 第一个参数为调用方法的对象,第二个参数为方法对应的参数列表
Object result=method.invoke(service,parameters);
return result;
}
.其请求中所需要三个参数 及时 类名,方法名,参数 可以封装成一个类 RPCRequest
4.server整体框架图
启动服务端
下面进行客户端的编写
1.client图
启动客户端
因为客户端只有接口,没有实现类,所以需要创建个代理类(JDK动态代理实现调用服务器方法) 提示:客户端和服务端通用的代码 比如 IHelloService
RPCRequest 等 可以提取出来
代理类:
代理类需要一个InvocationHandler 所以自定义一个RemoteInvocationHandler 把端口号和主机传递过去
这里需要定义一个传输层 (就是和服务端进行传递数据)
ublic class RPCNetTransport {
private String host;
private int port;
public RPCNetTransport() {
}
public RPCNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
private Socket newSocket(){
System.out.println("建立一个新的连接");
Socket socket=null;
try {
socket=new Socket(host,port);
} catch (Exception e) {
System.out.println("建立连接失败");
}
return socket;
}
public Object send(RPCRequest request){
Socket socket=null;
try {
//把客户端的数据request 直接发送过去
socket=newSocket();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(request);
objectOutputStream.flush();
//获取服务器返回的结果
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object result=objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
return result;
} catch (Exception e) {
throw new RuntimeException("数据发送异常"+e);
}finally {
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
基本功能就可以运行了 如下:
服务端:
客户端:
到此一个简单的RPC通信到此结束!