自定义RPC(完美实现两台机器之间调用服务)

本文详细介绍了如何实现自定义RPC框架,包括服务端接口的定义与实现,服务端注册中心的接口及其实现,客户端的构建,以及测试类中服务端注册中心的启动和客户端调用服务的执行结果。

自定义rpc

一、服务端暴露的接口

package remote.procedure.call.server;

public interface HelloService {
	public String sayHi(String name) ;//hi name
}

二、服务端功能接口实现类

package remote.procedure.call.server;
//实现类
public class HelloServiceImpl implements HelloService {

	@Override
	public String sayHi(String name) {
		System.out.println("你是傻逼!!!!!"+name);
		return "hi,"+name ;
	}

}


三、 服务端注册中心

(一)接口

package remote.procedure.call.server;

//服务中心
public interface Server {
	public void start() ;
	public void stop();
	//注册服务
	public void register(Class service,Class serviceImpl);
	//..
}

(二)实现类

	input.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
			
		}
		
	}
	
	
	
	

}

四、客户端

package remote.procedure.call.client;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client {
	//获取代表服务端接口的动�?�代理对象(HelloService�?
	//serviceInterface:请求的接口名
	//addr:待请求服务端的ip:端口
	@SuppressWarnings("unchecked")
	public static <T> T getRemoteProxyObj(Class serviceInterface,
											InetSocketAddress addr) {
		//newProxyInstance(a,b,c)
		/*
		 * a:类加载器 �?  �?要代理哪个类(例如HelloService接口),
		 * 就需要将HelloService的类加载�? 传入第一个参�?
		 * b:�?要代理的对象,具备哪些方�?  --接口  
		 * 单继承,多实�?  A implements B接口,c接口
		 * String str = new String();
		 * String[] str = new String[]{"aaa","bb","cc"} ;
		 */
		return  (T)Proxy.newProxyInstance(serviceInterface.getClassLoader(),
				new Class<?>[] {serviceInterface} , new InvocationHandler() {
			
			//proxy:代理的对�?, method:哪个方法(sayHello(参数列表)�?, args:参数列表
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) 
								throws Throwable {
				//客户端向服务端发送请求:请求某一个具体的接口
				Socket socket = new Socket();
				ObjectOutputStream output = null ; 
				 ObjectInputStream input = null ; 
				try {
				//socketaddress:  Ip:端�?
				socket.connect(addr);
				
				//发�?? :序列化流(对象流)
				  output =new ObjectOutputStream(    socket.getOutputStream()) ;
				 //接口�?  �? 方法�? :writeUTF
				 output.writeUTF(serviceInterface.getName());
				 output.writeUTF( method.getName() );
				 //方法参数的类型�?�方法参�?  Object   
				 output.writeObject( method.getParameterTypes()   );
				 output.writeObject(args);
				 //等待服务端处�?...
				 //接收服务端处理后的返回�??
				  input = new ObjectInputStream (socket.getInputStream()) ;
				 return input.readObject() ;//客户�?-服务�? ->返回�?
				}catch(Exception e) {
					e.printStackTrace();
					return null ;
				}finally {
					try {
						if(output!=null)output.close(); 
						if(input!=null) input.close() ; 
					}catch(Exception e) {
						e.printStackTrace();
					}
				}
			}
		}) ;
	}
}


五、 测试类

(一)启动服务端注册中心

package remote.procedure.call.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//服务中心的具体实现类
public class ServerCenter implements Server {
	// map:服务端, 可供客户端访问的接口,都注册到该map中
	// key:接口的名称,"HelloService" value:真正的HelloService实现
	private static HashMap<String, Class> serviceRegiser = new HashMap<>();
	private static int port;// = 9999
	//连接池:连接池中存在多个连接对象,每个连接对象都可以处理多个客户请求
	private static ExecutorService executor 
	= Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors()   ) ;

	private static boolean isRunning = false;
	
	public ServerCenter(int port) {
		this.port = port;
	}

	// �?启服务端服务
	@Override
	public void start() {//while(true){start();}
		
		//start ->线程对象  
		ServerSocket server = null ;
		try {
			server = new ServerSocket();
			server.bind(new InetSocketAddress(port));
		
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		isRunning = true ; //服务已经启动
		while(true) {
			//具体的服务内容:接收客户端请求,处理请求,并返回结果
				//100 :1  1   1 ...1  -->如果想让多个 客户端请求并发执�? 
				//-> 多线�?
				System.out.println("start  server....");
				//客户端每次请求一次连接(发出�?次请求),则服务�? 从连接池�? 
				//获取�?个线程对象去处理
				Socket socket = null ;
				try {
					 socket = server.accept();// 等待客户连接
				} catch (IOException e) {
					e.printStackTrace();
				}
				//启动线程 去处理客户请�?
				executor.execute(new ServiceTask(socket) );
			
		}
	}

	@Override
	public void stop() {//关闭服务
		isRunning = false ;
		executor.shutdown(); 
	}

	@Override
	public void register(Class service, Class serviceImpl) {
		serviceRegiser.put(service.getName(), serviceImpl);
	}
	
	//socket客户�?  - socket服务端(start() 、ServiceTask �?
	private static class ServiceTask implements Runnable{
		private Socket socket ; 
		public ServiceTask() {
		}
		public ServiceTask(Socket socket) {
			this.socket = socket ;
		}

		@Override
		public void run() {//线程�?做的事情
			ObjectOutputStream output = null;
			ObjectInputStream input = null;
			try {
				
			
		
			// 接收到客户端连接及请求,处理该请�?...
			input = new ObjectInputStream(socket.getInputStream()); //
			// 因为ObjectInputStream�? 发�?�数据的顺序 严格要求�?
			//因此�?要参照发送的顺序逐个接收
			String serviceName = input.readUTF();
			String methodName = input.readUTF();
			// 方法的参数类�? String Integer
			Class[] parameterTypes = (Class[]) input.readObject();
			// 方法的参数名
			Object[] arguments = (Object[]) input.readObject();
			// 根据客户请求,到map中找�? 与之对应�? 具体接口
			// HelloService
			Class ServiceClass = serviceRegiser.get(serviceName);

			Method method = ServiceClass.getMethod(methodName, parameterTypes);
			// 执行该方法
			System.out.println("调用并执行了服务端方法");
			Object result = method.invoke(ServiceClass.newInstance(), arguments); // person.say(参数列表);

			// 将发放执行完毕的返回�? 传给客户�?

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

}

执行结果:

start  server....
start  server....
调用并执行了服务端方法
你是傻逼!!!!!hellosss
start  server....
调用并执行了服务端方法
你是傻逼!!!!!e12e12

(二)测试客户端调用服务


package remote.procedure.call.test;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Socket;

import remote.procedure.call.client.Client;

public class RPCClientTest {
	public static void main(String[] args)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException,
			SecurityException, IllegalArgumentException, InvocationTargetException, IOException {

		InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 9999);

		// 第一种方式,通过动态代理,该方法由本机(即客户端)执行,没有用到rpc的精髓

		// 获取实例对象
		Object remoteProxyObj = Client.getRemoteProxyObj(Class.forName("remote.procedure.call.server.HelloService"),
				inetSocketAddress);
		// 获取实例对象方法
		Method method = remoteProxyObj.getClass().getMethod("sayHi", String.class);
		// 执行方法
		method.invoke(remoteProxyObj, "hellosss");

		// 第二种方式,通过套接字(本方法通过服务端执行)


		Socket socket = new Socket();
		socket.connect(inetSocketAddress);
		OutputStream outputStream = socket.getOutputStream();
		ObjectOutputStream out = new ObjectOutputStream(outputStream);
		out.writeUTF("remote.procedure.call.server.HelloService");
		out.writeUTF("sayHi");
		out.writeObject(new Class[] { String.class });
		out.writeObject(new Object[] { "e12e12" });
		out.flush();
		outputStream.flush();
		//读写必须一一对应不可或缺,否则可能报错
		ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
		//读取结果
		System.out.println("结果是:"+(Object) input.readObject());
		
		
		try {
			// out.close();//这里关闭会导致异常
			// outputStream.close();
			// socket.close();
		
			if (socket.isConnected()) {

				
				socket.close();
				System.out.println("关闭成功");
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println(e.getMessage());
		}

	}
}

执行结果:

结果是:hi,e12e12
关闭成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值