http://blog.csdn.net/zhu_tianwei/article/details/40887885

在一般使用RabbitMQ做RPC很容易。客户端发送一个请求消息然后服务器回复一个响应消息。为了收到一个响应,我们需要发送一个'回调'的请求的队列地址。我们可以使用默认队列(在Java客户端除外)。

AMQP协议给消息定义了14个属性。大部分的属性很少使用,除了下面几个:
  deliveryMode: 将消息标记为持久(值为2)或瞬态(任何其他值)。你可能记得在第二个教程中使用了这个属性。
  contentType:用来设置mime类型。例如经常使用的JSON格式数据,就需要将此属性设置为:application/json。
  replyTo: 通常用来命名一个回调队列.
  correlationId: 用来关联RPC请求的响应.

RPC工作流程:

1)、客户端启动时,创建了一个匿名的回调队列。
2)、在一个RPC请求中,客户端发送一个消息,它有两个属性:1.REPLYTO,用来设置回调队列名;2.correlationId,对于每个请求都被设置成唯一的值。
3)、请求被发送到rpc_queue队列.
4)、RPC工作者(又名:服务器)等待接收该队列的请求。当收到一个请求,它就会处理并把结果发送给客户端,使用的队列是replyTo字段指定的。
5)、客户端等待接收回调队列中的数据。当接到一个消息,它会检查它的correlationId属性。如果它和设置的相匹配,就会把响应返回给应用程序。

1、RPC服务器的RPCServer.java,接收消息调用rpc并返回结果

  1. package cn.slimsmart.rabbitmq.demo.rpc;
  2. import java.security.MessageDigest;
  3. import com.rabbitmq.client.AMQP;
  4. import com.rabbitmq.client.AMQP.BasicProperties;
  5. import com.rabbitmq.client.Channel;
  6. import com.rabbitmq.client.Connection;
  7. import com.rabbitmq.client.ConnectionFactory;
  8. import com.rabbitmq.client.QueueingConsumer;
  9. //RPC调用服务端
  10. public class RPCServer {
  11. private static final String RPC_QUEUE_NAME = "rpc_queue";
  12. public static void main(String[] args) throws Exception {
  13. //• 先建立连接、通道,并声明队列
  14. ConnectionFactory factory = new ConnectionFactory();
  15. factory.setHost("192.168.36.217");
  16. factory.setUsername("admin");
  17. factory.setPassword("admin");
  18. factory.setPort(AMQP.PROTOCOL.PORT);
  19. Connection connection = factory.newConnection();
  20. Channel channel = connection.createChannel();
  21. channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);
  22. //•可以运行多个服务器进程。通过channel.basicQos设置prefetchCount属性可将负载平均分配到多台服务器上。
  23. channel.basicQos(1);
  24. QueueingConsumer consumer = new QueueingConsumer(channel);
  25. //打开应答机制autoAck=false
  26. channel.basicConsume(RPC_QUEUE_NAME, false, consumer);
  27. System.out.println(" [x] Awaiting RPC requests");
  28. while (true) {
  29. QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  30. BasicProperties props = delivery.getProperties();
  31. BasicProperties replyProps = new BasicProperties.Builder()
  32. .correlationId(props.getCorrelationId()).build();
  33. String message = new String(delivery.getBody());
  34. System.out.println(" [.] getMd5String(" + message + ")");
  35. String response = getMd5String(message);
  36. //返回处理结果队列
  37. channel.basicPublish("", props.getReplyTo(), replyProps,
  38. response.getBytes());
  39. //发送应答
  40. channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  41. }
  42. }
  43. // 模拟RPC方法 获取MD5字符串
  44. public static String getMd5String(String str) {
  45. MessageDigest md5 = null;
  46. try {
  47. md5 = MessageDigest.getInstance("MD5");
  48. } catch (Exception e) {
  49. System.out.println(e.toString());
  50. e.printStackTrace();
  51. return "";
  52. }
  53. char[] charArray = str.toCharArray();
  54. byte[] byteArray = new byte[charArray.length];
  55. for (int i = 0; i < charArray.length; i++)
  56. byteArray[i] = (byte) charArray[i];
  57. byte[] md5Bytes = md5.digest(byteArray);
  58. StringBuffer hexValue = new StringBuffer();
  59. for (int i = 0; i < md5Bytes.length; i++) {
  60. int val = ((int) md5Bytes[i]) & 0xff;
  61. if (val < 16)
  62. hexValue.append("0");
  63. hexValue.append(Integer.toHexString(val));
  64. }
  65. return hexValue.toString();
  66. }
  67. }

2.客户端RPCClient.java,发送rpc调用消息,接收结果

  1. package cn.slimsmart.rabbitmq.demo.rpc;
  2. import com.rabbitmq.client.AMQP;
  3. import com.rabbitmq.client.Channel;
  4. import com.rabbitmq.client.Connection;
  5. import com.rabbitmq.client.ConnectionFactory;
  6. import com.rabbitmq.client.QueueingConsumer;
  7. import com.rabbitmq.client.AMQP.BasicProperties;
  8. //RPC调用客户端
  9. public class RPCClient {
  10. private Connection connection;
  11. private Channel channel;
  12. private String requestQueueName = "rpc_queue";
  13. private String replyQueueName;
  14. private QueueingConsumer consumer;
  15. public RPCClient() throws Exception {
  16. //• 先建立一个连接和一个通道,并为回调声明一个唯一的'回调'队列
  17. ConnectionFactory factory = new ConnectionFactory();
  18. factory.setHost("192.168.36.217");
  19. factory.setUsername("admin");
  20. factory.setPassword("admin");
  21. factory.setPort(AMQP.PROTOCOL.PORT);
  22. connection = factory.newConnection();
  23. channel = connection.createChannel();
  24. //• 注册'回调'队列,这样就可以收到RPC响应
  25. replyQueueName = channel.queueDeclare().getQueue();
  26. consumer = new QueueingConsumer(channel);
  27. channel.basicConsume(replyQueueName, true, consumer);
  28. }
  29. //发送RPC请求
  30. public String call(String message) throws Exception {
  31. String response = null;
  32. String corrId = java.util.UUID.randomUUID().toString();
  33. //发送请求消息,消息使用了两个属性:replyto和correlationId
  34. BasicProperties props = new BasicProperties.Builder()
  35. .correlationId(corrId).replyTo(replyQueueName).build();
  36. channel.basicPublish("", requestQueueName, props, message.getBytes());
  37. //等待接收结果
  38. while (true) {
  39. QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  40. //检查它的correlationId是否是我们所要找的那个
  41. if (delivery.getProperties().getCorrelationId().equals(corrId)) {
  42. response = new String(delivery.getBody());
  43. break;
  44. }
  45. }
  46. return response;
  47. }
  48. public void close() throws Exception {
  49. connection.close();
  50. }
  51. }

3、运行client主函数RPCMain.java

  1. package cn.slimsmart.rabbitmq.demo.rpc;
  2. public class RPCMain {
  3. public static void main(String[] args) throws Exception {
  4. RPCClient rpcClient = new RPCClient();
  5. System.out.println(" [x] Requesting getMd5String(abc)");
  6. String response = rpcClient.call("abc");
  7. System.out.println(" [.] Got '" + response + "'");
  8. rpcClient.close();
  9. }
  10. }

先运行服务端,再运行RPCMain,发送消息调用RPC。

这里介绍的是该设计不是实现RPC服务的唯一可能,但它有一些重要的优点:
1)如果RPC服务器速度太慢,你可以通过运行多个RPC服务器。尝试在一个新的控制台上运行第二RPCServer。
2)RPC客户端只发送和接收一个消息。不需要queueDeclare那样要求同步调用。因此,RPC客户端只需要在一个网络上发送和接收为一个单一的RPC请求。

(转) RabbitMQ学习之远程过程调用(RPC)(java)的更多相关文章

  1. RabbitMQ入门(6)——远程过程调用(RPC)

    在RabbitMQ入门(2)--工作队列中,我们学习了如何使用工作队列处理在多个工作者之间分配耗时任务.如果我们需要运行远程主机上的某个方法并等待结果怎么办呢?这种模式就是常说的远程过程调用(Remo ...

  2. RabbitMQ入门:远程过程调用(RPC)

    假如我们想要调用远程的一个方法或函数并等待执行结果,也就是我们通常说的远程过程调用(Remote Procedure Call).怎么办? 今天我们就用RabbitMQ来实现一个简单的RPC系统:客户 ...

  3. RabbitMQ学习(二):Java使用RabbitMQ要点知识

    转  https://blog.csdn.net/leixiaotao_java/article/details/78924863 1.maven依赖 <dependency> <g ...

  4. (转)RabbitMQ学习之主题topic(java)

    http://blog.csdn.net/zhu_tianwei/article/details/40887775 参考:http://blog.csdn.NET/lmj623565791/artic ...

  5. (转) RabbitMQ学习之发布/订阅(java)

    http://blog.csdn.net/zhu_tianwei/article/details/40887733 参考:http://blog.csdn.NET/lmj623565791/artic ...

  6. RabbitMQ学习第一记:用java连接RabbitMQ

    1.什么是RabbitMQ MQ(Message Queue):消息队列,是服务端设计的一个可以存储大量消息的队列,并提供客户端操作队列的方法:生产队列(向队列中添加数据).消费队列(从队列中取数据) ...

  7. RabbitMQ学习(一):RabbitMQ要点简介

    转载:http://blog.csdn.net/leixiaotao_java/article/details/78909760#t0 1.什么是RabbitMQ? RabbitMQ是由Erlang语 ...

  8. [译]RabbitMQ教程C#版 - 远程过程调用(RPC)

    先决条件 本教程假定 RabbitMQ 已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需要调整连接设置. 从哪里获得帮助 如果您在阅读本教程时遇到困难, ...

  9. java 执行sql错误 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。参数 1 (""): 数据类型 0x38 未知

    连接数据库时设置:Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE ,ResultSet.CONCUR_R ...

随机推荐

  1. 利用Socket 客户端---->服务端 传送文件到指定路径,并返回一个友好的回馈

    首先盲写的一个传输文件的方法,但测试发现了一个非常不容易发现的问题,这里先说明一下. 错误的代码如下: package com.TCP.java; import java.io.File; impor ...

  2. HDU4572 Bottles Arrangement

    /* HDU4572 Bottles Arrangement http://acm.hdu.edu.cn/showproblem.php?pid=4572 数论 找规律 题意:有m行n列和1-n的数各 ...

  3. 百度之星2014初赛 - 1002 - Grids

    先上题目: Grids Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Tota ...

  4. 转载 - 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题

    出处:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 ...

  5. git merge和git rebase的区别和异同

    1.git  merge和git rebase作用差不多,都是将远程代码和本地代码合并 2.git  merge和git rebase作用差不多,都是将远程代码和本地代码合并 3.git  merge ...

  6. 【小超_Android】android上开源的酷炫的交互动画和视觉效果:Interactive-animation

    1.交互篇 2.视觉篇 交互篇 1.SlidingUpPanelLayout 项目介绍:他的库提供了一种简单的方式来加入一个可拖动滑动面板(由谷歌音乐推广,谷歌地图和Rdio)你的Android应用程 ...

  7. phonegap(cordova) 自己定义插件代码篇(四)----读取本地图片

    有时候确实知道本地图片地址,要获取到base64  /** * 获取本地图片,包括路径和压缩后的 base64 */ (function (cordova) { var define = cordov ...

  8. Android 四大组件学习之ContentProvider二

    上节学习了什么是ContentProvider.以及ContentProvider的作用.以及什么是URL.本节就对上节学习的知识做一个实践,也就是定义自己的ContentProvider 好.实践是 ...

  9. 约瑟夫环问题的链表解法和数学解法(PHP)

    约瑟夫环问题 一群猴子排成一圈.按1,2,-,n依次编号.然后从第1仅仅開始数,数到第m仅仅,把它踢出圈.从它后面再開始数,再数到第m仅仅.在把它踢出去-.如此不停的进行下去.直到最后仅仅剩下一仅仅猴 ...

  10. [SCOI 2010] 股票交易

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1855 [算法] 单调队列优化动态规划 [代码] #include<bits/s ...