使用NIO来实现RPC

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yinbucheng/article/details/71640751

数据传输格式:

  客户端调用服务端:

    接口简单名/方法名(参数类型权限名:参数值, . ...)

    比如  SayHello/sayHello(java.lang.String:lalala)

     这里 接口名为SayHello    方法为 sayHello 参数类型为String 内容nana


服务端返回给客户端 

     返回类型:值


服务端代码:


import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;


/**
 * 它接受的内容是class/方法名(参数类型:参数,参数类型:参数)
 * 
 * @author Administrator
 * 
 */
public class RPCServer {
private static RPCServer instance = new RPCServer();
private HashMap<String, Object> str_obj = new HashMap<>();
private Selector selector;
private ServerSocketChannel ssc;


private RPCServer() {
try {
ssc = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(3003);
ssc.configureBlocking(false);
ssc.bind(address);
selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);

} catch (Exception e) {
throw new RuntimeException(e);
}
}


public static RPCServer getInstance() {
return instance;
}


public RPCServer addClass(Object obj) {
String name = obj.getClass().getInterfaces()[0].getSimpleName();
str_obj.put(name, obj);
return this;
}


// 开发服务等待连接
public void start() {
System.out.println("-----服务器已经启动了------");
ByteBuffer buff = ByteBuffer.allocate(1024);
try {
while (selector.select() > 0) {
for (SelectionKey sk : selector.selectedKeys()) {
selector.selectedKeys().remove(sk);
if (sk.isAcceptable()) {
// 调用accept方法接受连接,产生服务器端对应的SocketChannel
SocketChannel sc = ssc.accept();
// 设置采用非阻塞模式
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
// 将sk对应的Channel设置成准备接受其他请求
sk.interestOps(SelectionKey.OP_ACCEPT);
} else if (sk.isReadable()) {
// 获取该SelectionKey对应的Channel,该Channel中有可读的数据
SocketChannel sc = (SocketChannel) sk.channel();
try{
// 执行方法
remoteHandMethod(buff, sk, sc);
}catch(Exception e){
 //从Selector中删除指定的SelectionKey  
                       sk.cancel();  
                       if(sk.channel()!=null){  
                           sk.channel().close();  
                       }  
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}


private void remoteHandMethod(ByteBuffer buff, SelectionKey sk,
SocketChannel sc) throws IOException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException,
ClassNotFoundException {
buff.clear();
int read = sc.read(buff);
int postion = buff.position();//这里获取它真正的大小
byte[] data = buff.array();
String message = new String(data,0,postion);// class/方法名(参数类型:参数,参数类型:参数)
message = message.trim();
buff.clear();
String[] clazzData = message.split("/");
String className = clazzData[0];
String methodName = clazzData[1].substring(0,
clazzData[1].indexOf("("));
String temp = clazzData[1].substring(
clazzData[1].indexOf("(") + 1,
clazzData[1].indexOf(")"));
// 上一步的格式如下 1 "","string:nice"
String[] typeValues = decodeParamsTypeAndValue(temp);


Object object = str_obj.get(className);
Class clazz = object.getClass();
Object result = null;
if (typeValues == null) {
Method method = clazz.getDeclaredMethod(methodName,
null);
result = method.invoke(object, null);
} else {
Class[] types = new Class[typeValues.length];
Object[] values = new Object[typeValues.length];
for (int i = 0; i < typeValues.length; i++) {
String[] tv = typeValues[i].split(":");
String type = tv[0];
String value = tv[1];
types[i] = Class.forName(type);
if(type.contains("Integer")||type.contains("int"))
  values[i] = Integer.parseInt(value);
else if(type.contains("Float")||type.contains("float"))
values[i] = Float.parseFloat(value);
else if(type.contains("Double")||type.contains("double"))
    values[i] = Double.parseDouble(value);
else if(type.contains("Long")||type.contains("long"))
values[i] = Long.parseLong(value);
else
   values[i] = value; 
}
Method method = clazz.getDeclaredMethod(methodName,
types);
result = method.invoke(object,values);
}
if(result==null){
 result = "Void:null";
}else{
result = result.getClass().getSimpleName() + ":"
+ result;
}
// 发送结果回去
sc.write(ByteBuffer.wrap(result.toString()
.getBytes()));
sk.interestOps(SelectionKey.OP_READ);
}


// 它返回的格式是 参数类型:参数值
private String[] decodeParamsTypeAndValue(String params) {
if (params == null || params.equals(""))
return null;
if (params.indexOf(",") < 0)
return new String[] { params };
return params.split(",");


}
}


客户端代码:


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;


/**
 * 它所做的工作是利用代理封装方法
 * 
 * @author Administrator 问题是如何获取SocketChannel进行发送和接收
 */
public class RPCClient {
private SocketChannel channel;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
private static RPCClient client = new RPCClient();
private Selector selector = null;


private RPCClient() {
}


public static RPCClient getInstance() {
return client;
}


public RPCClient init(String serverIp) {
try {
System.out.println("------客户端要启动了--------");
selector = Selector.open();
InetSocketAddress isa = new InetSocketAddress(serverIp, 3003);


// 获取socket通道
channel = SocketChannel.open(isa);


// 连接服务器
channel.configureBlocking(false);


channel.register(selector, SelectionKey.OP_READ);


} catch (Exception e) {
throw new RuntimeException(e);
}
return this;
}


// 获取代理
public Object getRemoteProxy(final Class clazz) {
//动态产生实现类

return Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{clazz}, new InvocationHandler() {


@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO 自动生成的方法存根
String methodName = method.getName();
String clazzName = clazz
.getSimpleName();
Object result = null;
if (args == null || args.length == 0) {// 表示没有参数 它传递的类型
// 接口名/方法名()
channel.write(ByteBuffer
.wrap((clazzName + "/" + methodName + "()")
.getBytes()));
} else {
int size = args.length;
String[] types = new String[size];
StringBuffer content = new StringBuffer(clazzName)
.append("/").append(methodName).append("(");
for (int i = 0; i < size; i++) {
types[i] = args[i].getClass().getName();
content.append(types[i]).append(":").append(args[i]);
if (i != size - 1)
content.append(",");
}
content.append(")");
channel.write(ByteBuffer
.wrap(content.toString().getBytes()));
}
// 获取结果
result = getresult();


return result;
}
});


}


private Object getresult() {
// 解析结果 如果结尾为null或NULL则忽略
try {
while (selector.select() > 0) {
for (SelectionKey sk : selector.selectedKeys()) {
selector.selectedKeys().remove(sk);
if (sk.isReadable()) {
SocketChannel sc = (SocketChannel) sk.channel();
buffer.clear();
sc.read(buffer);
int postion = buffer.position();

String result = new String(buffer.array(),0,postion);
result = result.trim();
       buffer.clear();

if (result.endsWith("null") || result.endsWith("NULL"))
return null;


String[] typeValue = result.split(":");
String type = typeValue[0];
String value = typeValue[1];
if (type.contains("Integer") || type.contains("int"))
return Integer.parseInt(value);
else if (type.contains("Float")
|| type.contains("float"))
return Float.parseFloat(value);
else if(type.contains("Long")||type.contains("long"))
return Long.parseLong(value);
else
return value;
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}

}


调用如下:

public class RPCCTest {
   public static void main(String[] args) {
RPCClient client = RPCClient.getInstance();
client.init("127.0.01");
SayHello sayHello =  (SayHello) client.getRemoteProxy(SayHello.class);
System.out.println("client:"+sayHello.sayHello());
sayHello.sayHi("i am come from client");
System.out.println("1 + 4 = "+sayHello.sum(1, 2));
System.out.println("23 * 56 ="+sayHello.test2(23L, 56L));
 }


public class RPCSTest {
public static void main(String[] args) {
          RPCServer server = RPCServer.getInstance();
          server.addClass(new SayHelloBean());
          server.start();
}
}


运行启动RPCSTest 再启动RPCCTest

展开阅读全文

没有更多推荐了,返回首页