基于TCP协议的RPC

前言:

      本文内容的主体基于陈康贤先生的《大型分布式网站架构》,在写本文时,笔者提炼了书里的关键内容,并在一些地方加上了自己的见解,同时书中的关键代码或伪代码付诸实践。如有不足之处,欢迎指正。在有引用到其他书籍时,笔者做了标记,以助读者自行扩展阅读。同时也欢迎大家阅读陈康贤先生的这本书,站在巨人的肩膀上,看待如今的大型分布式网站。

 

内容提纲:

1、RPC简介

2、序列化与反序列化简介

3、基于TCP协议的一个RPC实例

 

正文:

一、RPC简介

  如果你去一家公司面试,面试官上来问你,什么是RPC,你不知道,可能就会失去这个入职的机会。不过也不用妄自菲薄,面试官问你关于RPC的知识,可能是他们项目组正在做分布式大型网站。如果你的专长不在这方面,自然也就不适合这个职位了,也并不是说你不够强。话虽这样,但自从2008年淘宝网改造成一个大型分布式网站之后,分布式越来越走向潮流,不仅如此,所谓的“云计算”、“大数据”好多也是基于分布式系统的。分布式意味着面对并发、业务复用、安全防御等方面的更高挑战。相信对大多数程序员来说,掌握这方面体系的知识,也是更高的挑战和荣誉。

  不论如何,分布式应用所要解决的首要问题,还是实现应用间的远程调用,这就是RPCRemote Process Call),字面上理解,就是不局限于本地方法去调用远程机器上的方法或进程。RPC的意义在于突破了单台服务器的处理能力,将本地调用转变为远程过程调用,从而给系统处理能力与吞吐量带来了无限制提升的可能。其实现方案现大多已成熟并得到广泛应用,代表性的包括RMIWebService等。

  关于RMIWebService,请参见林昊先生的《分布式java应用》第一章,里面有详细的讲解。

二、序列化与反序列化简介

  无论是何种数据,想实现远程传输,都要转化成二进制流。对象也是如此。

  定义:将对象转化为二进制流的过程称为对象的序列化;将二进制流恢复为对象的过程称为对象的反序列化。

  序列化和反序列化是十分基础的内容,大学的java课程中一般都有介绍。但话虽如此,序列化与反序列化是一块比较成体系的知识,有时间我会专门写一个这方面的博客来介绍和总结。在这之前,如果读者想具体了解,请参见《java与模式》一书中“javabean的冷藏与解冻”一章。

  序列化和反序列化实现方式比较简单,可通过Java内置的序列化方式或使用Hessian实现,后者需要引入第二方包hessian.jar。此处只提供给读者搜索的关键字,不赘述代码。

三、基于TCP协议的一个RPC实例

下面是这个实例的全部代码:

SayHelloService接口:

public interface SayHelloService {
    /**
     * 问好的接口
     * @param helloArg 参数
     * @return
     * */
    public String sayHello(String helloArg);
}


具体的服务类:

public class SayHelloServiceImpl implements SayHelloService {

    @Override
    public String sayHello(String helloArg) {
        if(helloArg.equals("hello")){
            return "hello";
        }else{
            return "bye bye";
        }
    }
}


服务消费者(客户端)代码:

public class Consumer {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, UnknownHostException, IOException, ClassNotFoundException {
        String interfacename = SayHelloService.class.getName();
        Method method = SayHelloService.class.getMethod("sayHello", java.lang.String.class);
        Object[] arguments = {"hello"};
        Socket socket = new Socket("127.0.0.1",1234);
        
        ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());

        output.writeUTF(interfacename);
        output.writeUTF(method.getName());
        output.writeObject(method.getParameterTypes());
        output.writeObject(arguments);
        
        
        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
        Object result = input.readObject();
        System.out.println("客户端接收到的消息:"+result.toString());
        
    }
}

服务提供者(服务器)代码:

public class Provider {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ServerSocket server = new ServerSocket(1234);
        
        SayHelloService ser = new  SayHelloServiceImpl();
        Map<String,SayHelloService> services = new HashMap<String,SayHelloService>();
        services.put("com.shuai.helloservice.SayHelloService", ser);
        
        
        while(true){
            Socket socket = server.accept();
            
            //读取信息
            ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
            String interfancename = input.readUTF(); //接口名称
            String methodName = input.readUTF(); //方法名称
            Class<?>[] parameterTypes = (Class<?>[])input.readObject(); //参数类型
            Object[] arguments = (Object[])input.readObject();
            System.out.println("服务器端收到的消息:"+arguments[0]);
            
            
            //执行调用
            Class serviceinterfaceclass = Class.forName(interfancename);
            Object service = services.get(interfancename); //获取服务实现的对象
            Method method = serviceinterfaceclass.getMethod(methodName, parameterTypes);
            Object result = method.invoke(service, arguments);
            
            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
            output.writeObject(result);
            System.out.println(result.toString()+"已发送给客户端");
        }
    }
    
}


运行结果:

服务器:
 

客户端:



注:本实例简化的内容主要包括

1、通过Socket发送数据时,本例采用阻塞式I/O,但实际多使用非阻塞式I/O,以提供更大的吞吐量。关于阻塞与非阻塞式I/O,参见林昊先生的《分布式java应用》第一章。

2、代码中services这个map用于存储事先准备好的服务实例,这里简化了这个过程,但实际上这一过程也有一套体系性知识点。之后介绍。

3、很明显,并没有处理并发等情况。

4、异常全部用throw方式,也是为了简洁。

 

下一章分享基于HTTP协议的RPC,希望我能坚持下来吧~~~~


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值