原文:RabbitMQ(二):理解消息通信RabbitMQ

一、消费者、生产者和信道

  生产者(producer):生产者创建消息,然后发布(发送)到代理服务器(RabbitMQ),可以说发送消息的程序就是生产者。什么是消息?消息包含两部分:有效载荷和标签。有效载荷就是传输的数据,可以是任何内容,包括json数据和图片等等。而标签(一个叫交换器名称和可选的主题标记)描述了有效载荷,RabbitMQ用它来决定谁将获得这个消息。

  消费者(consumer):消费者就是接收消息并处理消息的程序,他们连接到代理服务器上,并订阅到队列上。当消费者接收消息时,它只是得到消息的有效载荷。整个过程很简单:生产者创建消息,消费者接收消息。你的应用程序可以作为生产者也可以作为消费者,在两者之间切换。但是消息的传输必定会通过某一介质传递,此处的消息就通过信道传递。

  信道(channel):不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。应用程序和Rabbit代理服务器之间会创建一条TCP连接,TCP连接就像电缆,信道相当于电缆中的光束。在一条TCP连接上创建多少条信道是没有限制的,所以不会对操作系统的TCP栈造成额外的负担。

二、队列、交换器和绑定

  Rabbit的消息路由分为三部分:交换器、队列和绑定。生产者把消息发布到交换器上;消息最终到达队列,并被消费者接收;绑定决定了消息如何从路由器路由到特定的队列。

  队列(queue):队列是一个栈先进先出,为生产者发布的消息提供了保存的处所,消息在此等待消费。本质上队列可以存储无限的消息,但是需要视系统内存而定。

  绑定(binding):队列通过路由键绑定到交换器,路由键就是消息通过交换器投递到那个队列的规则。

  交换器(exchange):交换器有四种类型:direct、fanout、topic和headers。一个Exchange可以和多个Queue进行绑定,producer在传递消息的时候,会传递一个路由键,Exchange会根据这个路由键按照特定的路由算法,将消息路由给指定的queue。

  (1)direct:如果路由键匹配的话,消息就被投递到对应的队列。类似于单播。

  (2)fanout:将消息广播到绑定的队列上,不管路由键是什么,绑定的队列都会收到消息。

  (3)topic:类似与组播,和正则表达式类似,发送给路由键符合一定规则的队列。如:路由键为user.stock的消息会转发给绑定匹配模式为 * .stock,user.stock, * . * 和#.user.stock.#的队列(* 表是匹配一个任意词组,#表示匹配0个或多个词组)。

  (4)headers:不通过路由键匹配而是通过消息的header匹配,其他与direct交换器一致,但是性能上会差很多。

三、vhost

  每一个RabbitMQ服务器都能创建虚拟消息服务器,我们称之为虚拟主机(vhost)。每一个vhost本质上是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器和绑定,最重要的是拥有自己的权限机制。逻辑上vhost之间是相互独立的分离的,保证了安全性和可移植性。RabbitMQ包含了开箱即用的默认的vhost:"/",因此使用起来非常简单。当在RabbitMQ集群中创建vhost时,整个集群上都会创建该vhost,避免了vhost的重复创建。

四、第一次尝试消息通信

  交换器或队列的时候,如果交换器或队列已经存在,则直接返回结束,不会重复创建。无法承担消息丢失,则生产者和消费者中都需要尝试去创建交换器和队列,如果可以承担则可以由消费者来声明队列。我们创建生产者和消费者两个控制台程序分别运行以下代码。

  生产者:

  1. static void Main(string[] args)
  2. {
  3. FirstProducer();
  4. }
  5.  
  6. /// <summary>
  7. /// 第一个生产者
  8. /// </summary>
  9. private static void FirstProducer()
  10. {
  11. //1.连接到服务器
  12. var conn_factory = new ConnectionFactory() {
  13. HostName = "localhost",UserName="guest",Password="guest",Port=//默认端口5672
  14. };
  15. using (IConnection conn = conn_factory.CreateConnection())
  16. {
  17. //2.创建信道
  18. using (IModel channel = conn.CreateModel())
  19. {
  20. //3.声明交换器
  21. channel.ExchangeDeclare(
  22. "HelloExchange", //交换器名称
  23. ExchangeType.Direct,//交换器类型
  24. true, //是否持久话
  25. false, //是否自动删除
  26. null //关于交换器的详细设置,键值对形式
  27. );
  28. //4.声明队列
  29. channel.QueueDeclare(
  30. "HelloQueue",//队列名称
  31. false, //是否持久化
  32. false, //是否只对首次声明的队列可见
  33. false, //是否自动删除
  34. null ////关于队列和队列内消息的详细设置,键值对形式
  35. );
  36. //5.绑定交换器和队列
  37. channel.QueueBind(
  38. "HelloQueue", //队列名
  39. "HelloExchange", //交换器名
  40. "hola" //路由键
  41. );
  42. //6.发布消息
  43. string msg_str = "这是生产者第一次发布的消息";
  44. IBasicProperties msg_pro = channel.CreateBasicProperties();
  45. msg_pro.ContentType = "text/plain";//发布的数据类型
  46. for(int i = ; i < ; i++)
  47. {
  48. channel.BasicPublish(
  49. "HelloExchange", //消息发送目标交换器名称
  50. "hola", //路由键
  51. msg_pro, //消息的发布属性
  52. Encoding.UTF8.GetBytes(msg_str) //消息
  53. );
  54. }
  55. }
  56. }
  57. }

  消费者:

  1. static void Main(string[] args)
  2. {
  3. FirstCousmer();
  4. }
  5. /// <summary>
  6. /// 第一个消费者
  7. /// </summary>
  8. private static void FirstCousmer()
  9. {
  10. //1.链接到服务器
  11. var conn_factory = new ConnectionFactory()
  12. {
  13. HostName = "localhost",UserName = "guest",Password = "guest",Port =
  14. };
  15. using (var conn = conn_factory.CreateConnection())
  16. {
  17. //2.创建信道
  18. using(IModel channel = conn.CreateModel())
  19. {
  20. //3.声明交换器
  21. channel.ExchangeDeclare(
  22. "HelloExchange", //交换器名称
  23. ExchangeType.Direct,//交换器类型
  24. true, //是否持久话
  25. false, //是否自动删除
  26. null //关于交换器的详细设置,键值对形式
  27. );
  28. //4.声明队列
  29. channel.QueueDeclare(
  30. "HelloQueue",//队列名称
  31. false, //是否持久化
  32. false, //是否只对首次声明的队列可见
  33. false, //是否自动删除
  34. null ////关于队列和队列内消息的详细设置,键值对形式
  35. );
  36. //5.绑定交换器和队列
  37. channel.QueueBind(
  38. "HelloQueue", //队列名
  39. "HelloExchange", //交换器名
  40. "hola" //路由键
  41. );
  42. //6.获取消息
  43. var consumer = new EventingBasicConsumer(channel);
  44. consumer.Received += (ch, ea) => //消费者消息接收处理事件
  45. {
  46. var body = Encoding.UTF8.GetString(ea.Body);
  47. Console.WriteLine(body);
  48. channel.BasicAck(ea.DeliveryTag, false); //确认接收消息,从队列中删除
  49. };
  50. //7.启动消费者
  51. string consumer_tag = channel.BasicConsume(
  52. "HelloQueue", //获取的队列名称
  53. false, //是否自动确认接收消息,从队列中删除
  54. consumer //消费者对象
  55. );
  56. channel.BasicCancel(consumer_tag);//调用消费
  57. //var consumer = new QueueingBasicConsumer(channel);
  58. //channel.BasicConsume("HelloQueue", false, consumer);
  59. //while (true)
  60. //{
  61. // var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
  62. // var body = ea.Body;
  63. // var message = Encoding.UTF8.GetString(body);
  64. // Console.WriteLine("Received {0}", message);
  65. // channel.BasicAck(ea.DeliveryTag, false);
  66. //}
  67. }
  68. }
  69. Console.ReadLine();
  70. }

  运行消费者后可以看到,以下结果:

RabbitMQ(二):理解消息通信RabbitMQ的更多相关文章

  1. RabbitMQ实战:理解消息通信

    RabbitMQ是一个开源的消息代理和队列服务器,可以通过基本协议在完全不同的应用之间共享数据,可以将作业排队以便让分布式服务进行处理. 本篇介绍下消息通信,首先介绍基础概念,将这些概念映射到AMQP ...

  2. RabbitMQ详解(二)------消息通信的概念

    PS:近期在南宁出差,工作比较忙,所以更新会比较慢. 说到消息通信,可能我们首先会想到的是邮箱,QQ,微信,短信等等这些通信方式,这些通信方式都有发送者,接收者,还有一个中间存储离线消息的容器.但是这 ...

  3. 二、消息队列之如何在C#中使用RabbitMQ(转载)

    二.消息队列之如何在C#中使用RabbitMQ 1.什么是RabbitMQ.详见 http://www.rabbitmq.com/. 作用就是提高系统的并发性,将一些不需要及时响应客户端且占用较多资源 ...

  4. .Net RabbitMQ之消息通信 构建RPC服务器

    1.消息投递服务 RabbitMQ是一种消息投递服务,怎么理解这句话呢?即RabbitMQ即不是消息的生产者,也是消息的消费者.他就像现实生活中快递模式,消费者在电商网站上下单买了一件商品,此时对应的 ...

  5. 二、消息队列之如何在C#中使用RabbitMQ

    1.什么是RabbitMQ.详见 http://www.rabbitmq.com/. 作用就是提高系统的并发性,将一些不需要及时响应客户端且占用较多资源的操作,放入队列,再由另外一个线程,去异步处理这 ...

  6. 消息中间件系列三:使用RabbitMq原生Java客户端进行消息通信(消费者(接收方)自动确认模式、消费者(接收方)自行确认模式、生产者(发送方)确认模式)

    准备工作: 1)安装RabbitMQ,参考文章:消息中间件系列二:RabbitMQ入门(基本概念.RabbitMQ的安装和运行) 2.)分别新建名为OriginalRabbitMQProducer和O ...

  7. 分布式消息通信之RabbitMQ Tutorials

    目录 官网 1 Hello World! 1.1 生产者demo producer 1.2 消费者demo consumer 1.3 查看queue队列中的信息 页面查看,可看到有4条消息 命令查看 ...

  8. (二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念

    原文:(二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念 没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. Rabbit ...

  9. RabbitMQ入门教程(十二):消息确认Ack

    原文:RabbitMQ入门教程(十二):消息确认Ack 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csd ...

随机推荐

  1. DevOps 发展融合运维可视化

    DevOps,是开发(Development)和运维(Operations)的组合,代表一种文化.运动或实践,旨在促进软件交付和基础设施变更软件开发人员(Dev)和 IT 运维技术人员(Ops)之间的 ...

  2. STL中set和map

    set 可以认为是数学上的集合,集合中的元素不允许有重复.set特有的操作是高效的插入.删除和执行基本查找. set的插入方法是 insert,由于集合元素的唯一性,insert操作不一定会成功,in ...

  3. MySQL无法启动、服务没有报告任何错误&初次登陆错误的解决

    先以管理员身份运行cmd(右键单击左下角win菜单) 输入mysqld -install,net start mysql,下图是返回结果.报错情况以及修正之后的全过程 启动失败之后输入mysqld - ...

  4. oracle 闪回功能详解

    Oracle的闪回技术提供了一组功能,可以访问过去某一时间的数据并从人为错误中恢复.闪回技术是Oracle 数据库独有的,支持任何级别的恢复,包括行.事务.表和数据库范围.使用闪回特性,您可以查询以前 ...

  5. css中padding与margin

    CSS padding margin border属性详解 图解CSS padding.margin.border属性W3C组织建议把所有网页上的对像都放在一个盒(box)中,设计师可以通过创建定义来 ...

  6. 将CAGradientLayer用作maskView的遮罩图层

    将CAGradientLayer用作maskView的遮罩图层 说明 CAGradientLayer可以用作alpha遮罩,供maskView使用,这两种东西都是非常偏门的东西,但是,偏门不代表功能不 ...

  7. Nav 切换

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. Linux chattr 命令详解

    常见命令参数 A:即Atime,告诉系统不要修改对这个文件的最后访问时间. S:即Sync,一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘. a:即Append Only,系统只允 ...

  9. 申请Let’s Encrypt永久免费SSL证书过程教程及常见问题

    配置证书https://easy.zhetao.com/   虽然目前Let’s Encrypt免费SSL证书默认是90天有效期,但是我们也可以到期自动续约,不影响我们的尝试和使用,为了考虑到文章的真 ...

  10. TreeSet的自然排序(自定义对象 compareTo方法)

    >要实现自然排序,对象集合必须实现Comparable接口,并重写compareTo()方法 >一般需求中描述的是"主要条件",如:按姓名长度排序.  需注意次要条件 ...