RPC功能的实现

来源:互联网 发布:变态的皇帝知乎 编辑:程序博客网 时间:2024/06/03 13:34

看了一下网络上关于rabbitMq实现RPC都是在服务端实现一个产生斐波那契数列的函数,然后将结果返回给客户端打印,所以索性去官网看了一下这一块的相关内容,但是官网上给的例子好像也是这个(晕...),既然那个例子这么经典,那么必然值得研究一下~

首先需要明确几个概念:

1.Callback queue 回调队列

一个客户端向服务器发送请求,服务器端处理请求后,将其处理结果保存在一个存储体中。而客户端为了获得处理结果,那么客户在向服务器发送请求时,同时发送一个回调队列地址。

2.Correlation id 关联标识

一个客户端可能会发送多个请求给服务器,当服务器处理完后,客户端无法辨别在回调队列中的响应具体和那个请求时对应的。为了处理这种情况,客户端在发送每个请求时,同时会附带一个独有correlation_id属性,这样客户端在回调队列中根据correlation_id字段的值就可以分辨此响应属于哪个请求。

同时RPC又分为异步和同步,这里采用异步队列的方式实现RPC功能。

流程:

1.客户端初始化

    启动后,创建一个独有的回调队列

2.客户端发送请求

    某个应用将请求信息交给客户端,然后客户端发送RPC请求,在发送RPC请求到RPC请求队列时,客户端至少发送带有reply_to以及correlation_id两个属性的信息

3.服务端接收请求

   等待接受客户端发来RPC请求,当请求出现的时候,服务器从RPC请求队列中取出请求,然后处理后,将响应发送到reply_to指定的回调队列中

4.客户端接收请求

    客户端等待回调队列中出现响应,当响应出现时,它会根据响应中correlation_id字段的值,将其返回给对应的应用



相关代码:

客户端:

public class Client {    private Connection connection;    private Channel channel;    private String requestQueueName = "rpc_queue";    private String replyQueueName;    private QueueingConsumer consumer;    public Client() throws Exception {        ConnectionFactory factory = new ConnectionFactory();        factory.setHost("localhost");        connection = factory.newConnection();        channel = connection.createChannel();        replyQueueName = channel.queueDeclare().getQueue();        consumer = new QueueingConsumer(channel);        channel.basicConsume(replyQueueName, true, consumer);    }    public String call(String message) throws Exception {        String response = null;        String corrId = UUID.randomUUID().toString();        BasicProperties props = new BasicProperties.Builder().correlationId(corrId).replyTo(replyQueueName).build();        channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8"));        while (true) {            QueueingConsumer.Delivery delivery = consumer.nextDelivery();            if (delivery.getProperties().getCorrelationId().equals(corrId)) {                response = new String(delivery.getBody(), "UTF-8");                break;            }        }            return response;    }    public void close() throws Exception {        connection.close();    }    public static void main(String[] argv) {        Client fibonacciRpc = null;        String response = null;        try {            fibonacciRpc = new Client();            System.out.println("RPCClient [x] Requesting fib(30)");            response = fibonacciRpc.call("30");            System.out.println("RPCClient [.] Got '" + response + "'");        } catch (Exception e) {            e.printStackTrace();        } finally {            if (fibonacciRpc != null) {                try {                    fibonacciRpc.close();                } catch (Exception ignore) {                }            }        }    }}


服务端

public class Server {    private static final String RPC_QUEUE_NAME = "rpc_queue";    private static int fib(int n) {        if (n == 0)            return 0;        if (n == 1)            return 1;        return fib(n - 1) + fib(n - 2);    }    public static void main(String[] argv) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory factory = new ConnectionFactory();            factory.setHost("localhost");            connection = factory.newConnection();            channel = connection.createChannel();            channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);            channel.basicQos(1);            QueueingConsumer consumer = new QueueingConsumer(channel);            channel.basicConsume(RPC_QUEUE_NAME, false, consumer);            System.out.println("RPCServer [x] Awaiting RPC requests");            while (true) {                String response = null;                QueueingConsumer.Delivery delivery = consumer.nextDelivery();                BasicProperties props = delivery.getProperties();                BasicProperties replyProps = new BasicProperties.Builder().correlationId(props.getCorrelationId()).build();                try {                    String message = new String(delivery.getBody(), "UTF-8");                    int n = Integer.parseInt(message);                    System.out.println("RPCServer [.] fib(" + message + ")");                    response = "" + fib(n);                } catch (Exception e) {                    System.out.println(" [.] " + e.toString());                    response = "";                } finally {                    channel.basicPublish("", props.getReplyTo(), replyProps, response.getBytes("UTF-8"));                    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);                }            }        } catch (Exception e) {            e.printStackTrace();        } finally {            if (connection != null) {                try {                    connection.close();                } catch (Exception ignore) {                }            }        }    }}

参考文章:

https://www.rabbitmq.com/tutorials/tutorial-six-java.html

http://www.jianshu.com/p/13055d276f96