在上一篇的最后,编写了一个C#驱动RabbitMQ的简单栗子,了解了C#驱动RabbitMQ的基本用法。本章介绍RabbitMQ的四种Exchange及各种Exchange的使用场景。

1 direct类型

1 direct路由规则

   上一篇最后一个栗子使用的Exchange就是direct类型的,direct类型的exchange路由规则很简单:

  exchange在和queue进行binding时会设置routingkey(为了避免和下边的routingKey混淆,很多时候把这里的routingKey叫做BindingKey)

  1. channel.QueueBind(queue:"Q1", exchange:"myexchange", routingKey:"orange");

  将消息发送到Broker时会设置对应的routingkey

  1. channel.BasicPublish(exchange: "myexchange",routingKey: "orange", basicProperties: null, body: body);

  只有RoutingKey和BindingKey完全相同时,exchange才会把消息路由到绑定的queue中去

2 代码示例

  我们知道了direact类型的交换机只有routingKey和bindingKey相同的时候才会进行消息路由,根据这一特点我们可以通过routingKey将消息路由到不同的queue中。如在进行日志处理时,需求是所有的日志都保存到文本文件,出现错误日志时则还需要短信通知以便及时处理。我们可以创建两个队列:只接收错误日志的log_error队列和接收所有日志信息的log_all队列。消费者C1处理log_error队列中消息,将这些消息通过短信通知管理员,消费者C2处理log_all队列的信息,将这些信息记录到文本文件。

  生产者用于发送日志消息,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. HostName = "127.0.0.1",
  6. UserName = "wyy",//用户名
  7. Password = ""//密码
  8. };
  9. //创建连接connection
  10. using (var connection = factory.CreateConnection())
  11. {
  12. //创建通道channel
  13. using (var channel = connection.CreateModel())
  14. {
  15. //声明交换机exchang
  16. channel.ExchangeDeclare(exchange: "myexchange",
  17. type: ExchangeType.Direct,
  18. durable: true,
  19. autoDelete: false,
  20. arguments: null);
  21. //声明两个队列,log_all保存所有日志,log_error保存error类型日志
  22. channel.QueueDeclare(queue: "log_all",
  23. durable: true,
  24. exclusive: false,
  25. autoDelete: false,
  26. arguments: null);
  27. channel.QueueDeclare(queue: "log_error",
  28. durable: true,
  29. exclusive: false,
  30. autoDelete: false,
  31. arguments: null);
  32. //绑定所有日志类型到log_all队列
  33. string[] logtypes = new string[] { "debug", "info", "warn", "error" };
  34. foreach (string item in logtypes)
  35. {
  36. channel.QueueBind(queue: "log_all",
  37. exchange: "myexchange",
  38. routingKey: item);
  39. }
  40. //绑定错误日志到log_all队列
  41. channel.QueueBind(queue: "log_error",
  42. exchange: "myexchange",
  43. routingKey: "error");
  44. //准备100条测试日志信息
  45. List<LogMsg> msgList = new List<LogMsg>();
  46. for (int i = ; i < ; i++)
  47. {
  48. if (i%==)
  49. {
  50. msgList.Add(new LogMsg() { LogType = "info", Msg = Encoding.UTF8.GetBytes($"info第{i}条信息") });
  51. }
  52. if (i % == )
  53. {
  54. msgList.Add(new LogMsg() { LogType = "debug", Msg = Encoding.UTF8.GetBytes($"debug第{i}条信息") });
  55. }
  56. if (i % == )
  57. {
  58. msgList.Add(new LogMsg() { LogType = "warn", Msg = Encoding.UTF8.GetBytes($"warn第{i}条信息") });
  59. }
  60. if (i % == )
  61. {
  62. msgList.Add(new LogMsg() { LogType = "error", Msg = Encoding.UTF8.GetBytes($"error第{i}条信息") });
  63. }
  64. }
  65. Console.WriteLine("生产者发送100条日志信息");
  66. //发送日志信息
  67. foreach (var item in msgList)
  68. {
  69. channel.BasicPublish(exchange: "myexchange",
  70. routingKey: item.LogType,
  71. basicProperties: null,
  72. body: item.Msg);
  73. }
  74. }
  75. }
  76. Console.ReadKey();
  77. }
  78. }

  消费者C1用于处理log_error队列中的消息,错误消息进行短信通知,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "myexchange",
  18. type: ExchangeType.Direct,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列queue
  23. channel.QueueDeclare(queue: "log_all",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28.  
  29. //绑定
  30. channel.QueueBind(queue: "log_error",
  31. exchange: "myexchange",
  32. routingKey: "error");
  33.  
  34. //定义消费者
  35. var consumer = new EventingBasicConsumer(channel);
  36. consumer.Received += (model, ea) =>
  37. {
  38. var body = ea.Body;
  39. var message = Encoding.UTF8.GetString(body);
  40. //只是为了演示,并没有存入文本文件
  41. Console.WriteLine($"接收成功!【{message}】,发送短信通知");
  42. };
  43. Console.WriteLine("消费者C1【接收错误日志,发送短信通知】准备就绪....");
  44. //处理消息
  45. channel.BasicConsume(queue: "log_error",
  46. autoAck: true,
  47. consumer: consumer);
  48. Console.ReadLine();
  49. }
  50. }
  51. }

  消费者C2用于处理log_all队列中的消息,所有消息记录到文本文件中,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "myexchange",
  18. type: ExchangeType.Direct,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列queue
  23. channel.QueueDeclare(queue: "log_all",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28.  
  29. //绑定
  30. string[] logtypes = new string[] { "debug", "info", "warn", "error" };
  31. foreach (string item in logtypes)
  32. {
  33. channel.QueueBind(queue: "log_all",
  34. exchange: "myexchange",
  35. routingKey: item);
  36. }
  37. //定义消费者
  38. var consumer = new EventingBasicConsumer(channel);
  39. consumer.Received += (model, ea) =>
  40. {
  41. var body = ea.Body;
  42. var message = Encoding.UTF8.GetString(body);
  43. //只是为了演示,并没有存入文本文件
  44. Console.WriteLine($"接收成功!【{message}】,存入文本文件");
  45. };
  46. Console.WriteLine("消费者C2【接收所有日志信息,存入文本文件】准备就绪....");
  47. //处理消息
  48. channel.BasicConsume(queue: "log_all",
  49. autoAck: true,
  50. consumer: consumer);
  51. Console.ReadLine();
  52. }
  53. }
  54. }

  运行这三个项目,执行结果如下:

2 fanout类型

1 fanout路由规则

  fanout类型的exchange路由规则是最简单的,交换机会把消息广播到与该Exchange绑定的所有queue中,即所有和该exchange绑定的队列都会收到消息。fanout类型exchange和队列绑定时不需要指定routingKey,即使指定了routingKey也会被忽略掉。路由结构如下:

  fanout类型交换机主要用于发布/订阅的一些场景,如用户注册了我们的网站后,我们通过短信和邮件两种方式通知用户

2 代码示例

  这里通过代码简单演示将消息同时使用短信和邮件两种方式通知用户的流程。首先声明一个fanout类型的exchange,然后声明两个队列 SMSqueue和EMAILqueue,这两个队列都和这个exchange绑定。消费者1处理EMAILqueue的消息,通过邮件方式发送通知;消费者2处理SMSqueue的消息通过短信方式发送通知。

  生产者发送信息,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //第一步:创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "myfanoutexchange",
  18. type: ExchangeType.Fanout,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明SMSqueue队列,用于短信通知
  23. channel.QueueDeclare(queue: "SMSqueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28. //声明队列,Email队列,用于邮件通知
  29. channel.QueueDeclare(queue: "EMAILqueue",
  30. durable: true,
  31. exclusive: false,
  32. autoDelete: false,
  33. arguments: null);
  34.  
  35. //绑定exchange和queue
  36. channel.QueueBind(queue: "SMSqueue", exchange: "myfanoutexchange", routingKey: string.Empty,arguments:null);
  37. channel.QueueBind(queue: "EMAILqueue", exchange: "myfanoutexchange", routingKey: string.Empty, arguments: null);
  38. Console.WriteLine("生产者准备就绪....");
  39.  
  40. string message = "";
  41. //第六步:发送消息
  42. //在控制台输入消息,按enter键发送消息
  43. while (!message.Equals("quit", StringComparison.CurrentCultureIgnoreCase))
  44. {
  45. message = Console.ReadLine();
  46. var body = Encoding.UTF8.GetBytes(message);
  47. //基本发布
  48. channel.BasicPublish(exchange: "myfanoutexchange",
  49. routingKey: string.Empty,
  50. basicProperties: null,
  51. body: body);
  52. Console.WriteLine($"消息【{message}】已发送到队列");
  53. }
  54. }
  55. }
  56. Console.ReadKey();
  57. }

  消费者1将EMAILqueue的消息通过邮件方式发送通知,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "myfanoutexchange",
  18. type: ExchangeType.Fanout,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列queue
  23. channel.QueueDeclare(queue: "EMAILqueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28.  
  29. //绑定exchange和queue
  30. channel.QueueBind(queue: "EMAILqueue", exchange: "myfanoutexchange", routingKey: string.Empty, arguments: null);
  31. //定义消费者
  32. var consumer = new EventingBasicConsumer(channel);
  33. consumer.Received += (model, ea) =>
  34. {
  35. var body = ea.Body;
  36. var message = Encoding.UTF8.GetString(body);
  37. //只是为了演示,并没有存入文本文件
  38. Console.WriteLine($"接收成功!【{message}】,邮件通知");
  39. };
  40. Console.WriteLine("邮件通知服务准备就绪...");
  41. //处理消息
  42. channel.BasicConsume(queue: "EMAILqueue",
  43. autoAck: true,
  44. consumer: consumer);
  45. Console.ReadLine();
  46. }
  47. }
  48. }

  消费者2将SMSqueue的消息通过短信方式发送通知,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "myfanoutexchange",
  18. type: ExchangeType.Fanout,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列queue
  23. channel.QueueDeclare(queue: "SMSqueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28.  
  29. //绑定exchange和queue
  30. channel.QueueBind(queue: "SMSqueue", exchange: "myfanoutexchange", routingKey: string.Empty,arguments:null);
  31. //定义消费者
  32. var consumer = new EventingBasicConsumer(channel);
  33. consumer.Received += (model, ea) =>
  34. {
  35. var body = ea.Body;
  36. var message = Encoding.UTF8.GetString(body);
  37. //只是为了演示,并没有存入文本文件
  38. Console.WriteLine($"接收成功!【{message}】,短信通知");
  39. };
  40. Console.WriteLine("短信通知服务准备就绪...");
  41. //处理消息
  42. channel.BasicConsume(queue: "myfanoutqueue",
  43. autoAck: true,
  44. consumer: consumer);
  45. Console.ReadLine();
  46. }
  47. }
  48. }

  启动这三个应用程序,执行结果如下:

3 topic类型

1 topic路由规则

  topic类型exchange的路由规则也是基于routingKey和bindingKey的,其路由过程和direct类型基本一致,两者的区别在于direct类型的exchange要求routingKey和bindingKey必须相同才进行将消息路由到绑定的queue中,而topic类型的bindingKey是一个匹配规则,只要routingKey符合bindingKey的规则就可以将消息路由到绑定的queue中去,结构如下图所示。注意routingKey和bindingKey的结构都是一系列由点号连接单词的字符串,例如【aaa.bbb.ccc】。

  bindingKey的两个特殊符号:*表示一个单词,#表示0或多个单词(注意是单词,而不是字符)。如下图,usa.news和usa.weather都和usa.#匹配,而usa.news和europe.news都和#.news匹配。

  

2 代码实现

  这里使用代码实现上图中的例子,为了方便我们只定义两个队列:接收美国相关信息的usaQueue(bindingKey是usa.#)和接收新闻消息的newsQueue(bindingKey是#.news)。然后定义两个消费者,消费者1处理useaQueue的消息,消费者2处理newsQueue的消息。

  生产者代码:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "mytopicExchange",
  18. type: ExchangeType.Topic,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列usaQueue
  23. channel.QueueDeclare(queue: "usaQueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28. //声明队列newsQueue
  29. channel.QueueDeclare(queue: "newsQueue",
  30. durable: true,
  31. exclusive: false,
  32. autoDelete: false,
  33. arguments: null);
  34. Console.WriteLine("生产者准备就绪....");
  35. //绑定usaQueue队列到交互机,routingKey为usa.#
  36. channel.QueueBind(queue: "usaQueue", exchange: "mytopicExchange", routingKey: "usa.#", arguments: null);
  37. //绑定newsQueue队列到交互机,routingKey为#.news
  38. channel.QueueBind(queue: "newsQueue", exchange: "mytopicExchange", routingKey: "#.news", arguments: null);
  39.  
  40. ////--------------------开始发送消息
  41. //1.发送美国新闻消息
  42. string message1 = "美国新闻消息:内容balabala";
  43. var body1 = Encoding.UTF8.GetBytes(message1);
  44. channel.BasicPublish(exchange: "mytopicExchange",
  45. routingKey: "usa.news",
  46. basicProperties: null,
  47. body: body1);
  48. Console.WriteLine($"消息【{message1}】已发送到队列");
  49.  
  50. //2.发送美国天气消息
  51. string message2 = "美国天气消息:内容balabala";
  52. var body2 = Encoding.UTF8.GetBytes(message2);
  53. channel.BasicPublish(exchange: "mytopicExchange",
  54. routingKey: "usa.weather",
  55. basicProperties: null,
  56. body: body2);
  57. Console.WriteLine($"消息【{message2}】已发送到队列");
  58. //3.发送欧洲新闻消息
  59. string message3 = "欧洲新闻消息:内容balabala";
  60. var body3 = Encoding.UTF8.GetBytes(message3);
  61. channel.BasicPublish(exchange: "mytopicExchange",
  62. routingKey: "europe.news",
  63. basicProperties: null,
  64. body: body3);
  65. Console.WriteLine($"消息【{message3}】已发送到队列");
  66.  
  67. //4.发送欧洲天气消息
  68. string message4 = "欧洲天气消息:内容balabala";
  69. var body4 = Encoding.UTF8.GetBytes(message4);
  70. //基本发布
  71. channel.BasicPublish(exchange: "mytopicExchange",
  72. routingKey: "europe.weather",
  73. basicProperties: null,
  74. body: body4);
  75. Console.WriteLine($"消息【{message4}】已发送到队列");
  76. }
  77. }
  78. Console.ReadKey();
  79. }

  消费者1代码,只处理usaQueue中的消息:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "mytopicExchange",
  18. type: ExchangeType.Topic,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列queue
  23. channel.QueueDeclare(queue: "usaQueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28. Console.WriteLine("usaQueue消费者准备就绪....");
  29. //绑定usaQueue队列到交互机
  30. channel.QueueBind(queue: "usaQueue", exchange: "mytopicExchange", routingKey: "usa.#", arguments: null);
  31. //定义消费者
  32. var consumer = new EventingBasicConsumer(channel);
  33. consumer.Received += (model, ea) =>
  34. {
  35. var body = ea.Body;
  36. var message = Encoding.UTF8.GetString(body);
  37. Console.WriteLine($"接收成功!【{message}】");
  38. };
  39. //处理消息
  40. channel.BasicConsume(queue: "usaQueue",
  41. autoAck: true,
  42. consumer: consumer);
  43. Console.ReadLine();
  44. }
  45. }
  46. }

  消费者2代码,只处理newsQueue中的消息:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "mytopicExchange",
  18. type: ExchangeType.Topic,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明队列queue
  23. channel.QueueDeclare(queue: "newsQueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28. Console.WriteLine("newsQueue消费者准备就绪....");
  29. //绑定usaQueue队列到交互机
  30. channel.QueueBind(queue: "newsQueue", exchange: "mytopicExchange", routingKey: "#.news", arguments: null);
  31. //定义消费者
  32. var consumer = new EventingBasicConsumer(channel);
  33. consumer.Received += (model, ea) =>
  34. {
  35. var body = ea.Body;
  36. var message = Encoding.UTF8.GetString(body);
  37. Console.WriteLine($"接收成功!【{message}】");
  38. };
  39. //处理消息
  40. channel.BasicConsume(queue: "newsQueue",
  41. autoAck: true,
  42. consumer: consumer);
  43. Console.ReadLine();
  44. }
  45. }
  46. }

  生成者发送的四条消息中,消息1的routingKey为usa.news,同时符合usaQueue的bindingKey(usa.#)和newsQueue的bindingKey(#.news),所以消息1同时路由到两个队列中;消息2的routingKey为usa.weather只符合usa.#,发送到usaQueue;消息的rouKey为europe.news,只符合#.news,发送到newsQueue中;消息4的routingKey为europe.weahter,和两个队列的bindingKey都不符合,所以被丢弃。执行这三个Console应用程序,结果如下:

  一点补充:topic类型交换机十分灵活,可以轻松实现direct和fanout类型交换机的功能。如果绑定队列时所有的bindingKey都是#,则交换机和fanout类型交换机表现一致;如果所有的bindingKey都不包含*和#,则交换机和direct类型交换机表现一致。

4  header类型

1 header路由规则

  header类型路由规则和上边的几种exchange都不一样,header类型exchange不是通过routingKey进行路由的,而是通过Headers。exchange在和queue进行binding时可以设置arguments:

  1. channel.QueueBind(queue: "Allqueue",
  2. exchange: "myheaderExchange",
  3. routingKey: string.Empty,
  4. arguments: new Dictionary<string, object> {
  5. { "x-match","all"},
  6. { "user","jack"},
  7. { "pass",""}
                  
    });

  将消息发送到exchange时可以设置消息的Header:

  1. var props1 = channel.CreateBasicProperties();
  2. props1.Headers = new Dictionary<string, object>() {
  3. { "user","jack"},
  4. { "pass",""}
  5. };
  6. var body1 = Encoding.UTF8.GetBytes(msg1);
  7. //发送消息
  8. channel.BasicPublish(exchange: "myheaderExchange",
  9. routingKey: string.Empty,
  10. basicProperties: props1,
  11. body: body1);

  user和pass是普通的键值对,我们也可以设置其他的键值对。x-match是一个特殊的属性,当x-match为all时,agumentsbasicProrperties.Headers的所有键值对都相等时才会路由到queue(AND关系);当x-match为any时,aguments和basicProrperties.Headers的键值对只要有一个相同就可以路由到queue(OR关系)。

2.代码示例

  看一个简单的栗子,创建两个队列Allqueue和Anyqueue,其中Allqueue和exchange绑定时的x-match为all,Anyqueue和exchange绑定时的x-match为any;然后发送两条消息,发送第一条消息时basicProperties.Headers中的user和pass都和绑定队列时的agruments的user和pass相等,发送第二条消息是两者的pass不相等,代码如下:

  1. static void Main(string[] args)
  2. {
  3. var factory = new ConnectionFactory()
  4. {
  5. //rabbitmq-server所在设备ip,这里就是本机
  6. HostName = "127.0.0.1",
  7. UserName = "wyy",//用户名
  8. Password = ""//密码
  9. };
  10. //创建连接connection
  11. using (var connection = factory.CreateConnection())
  12. {
  13. //创建通道channel
  14. using (var channel = connection.CreateModel())
  15. {
  16. //声明交换机exchang
  17. channel.ExchangeDeclare(exchange: "myheaderExchange",
  18. type: ExchangeType.Headers,
  19. durable: true,
  20. autoDelete: false,
  21. arguments: null);
  22. //声明Allqueue队列
  23. channel.QueueDeclare(queue: "Allqueue",
  24. durable: true,
  25. exclusive: false,
  26. autoDelete: false,
  27. arguments: null);
  28. //声明Anyqueue队列
  29. channel.QueueDeclare(queue: "Anyqueue",
  30. durable: true,
  31. exclusive: false,
  32. autoDelete: false,
  33. arguments: null);
  34. Console.WriteLine("生产者准备就绪....");
  35.  
  36. //////发送消息消息1,user和pass都相同
  37. //绑定exchange和Allqueue
  38. channel.QueueBind(queue: "Allqueue",
  39. exchange: "myheaderExchange",
  40. routingKey: string.Empty,
  41. arguments: new Dictionary<string, object> {
  42. { "x-match","all"},
  43. { "user","jack"},
  44. { "pass",""}});
  45. string msg1 = "user和pass都相同时发送的消息";
  46. var props1 = channel.CreateBasicProperties();
  47. props1.Headers = new Dictionary<string, object>() {
  48. { "user","jack"},
  49. { "pass",""}
  50. };
  51. var body1 = Encoding.UTF8.GetBytes(msg1);
  52. //基本发布
  53. channel.BasicPublish(exchange: "myheaderExchange",
  54. routingKey: string.Empty,
  55. basicProperties: props1,
  56. body: body1);
  57. Console.WriteLine($"消息【{msg1}】已发送到队列");
  58.  
  59. //////发送消息消息2,user和pass不完全相同
  60. //绑定exchange和Anyqueue
  61. channel.QueueBind(queue: "Anyqueue",
  62. exchange: "myheaderExchange",
  63. routingKey: string.Empty,
  64. arguments: new Dictionary<string, object> {
  65. { "x-match","any"},
  66. { "user","jack"},
  67. { "pass",""},});
  68.  
  69. string msg2 = "user和pass不完全相同时发送的消息";
  70. var props2 = channel.CreateBasicProperties();
  71. props2.Headers = new Dictionary<string, object>() {
  72. { "user","jack"},
  73. { "pass",""}//这里的pass和BindQueue方法的中argumens中的pass不相同
  74. };
  75. var body2 = Encoding.UTF8.GetBytes(msg2);
  76. //基本发布
  77. channel.BasicPublish(exchange: "myheaderExchange",
  78. routingKey: string.Empty,
  79. basicProperties: props2,
  80. body: body2);
  81. Console.WriteLine($"消息【{msg2}】已发送到队列");
  82.  
  83. }
  84. }
  85. Console.ReadKey();
  86. }
  87. }

  执行程序,打开WebUI管理界面,结果如下,我们看到只有user和pass都相等时消息才会路由到Allqueue;user和pass只要有一个相等就会路由到Anyqueue

5 小结

  RabbitMQ的交换机(exchange)的作用是路由消息,我们可以根据应用场景的不同选择合适的交换机。如果需要精准路由到队列,或者对消息进行单一维度分类(只对日志的严重程度这一维度进行分类)可以使用direct类型交换机;如果需要广播消息,可以使用fanout类型的交换机;如果对消息进行多维度分类(如例子中按照地区和消息内容类型两个维度进行分类)使用topic类型的交换机;如果消息归类的逻辑包含了较多的AND/OR逻辑判断可以使用header类型交换机(开发中很少用到Header类型,官网上关于Header类型的介绍也不多)。

【参考文章】

1. https://www.cnblogs.com/zhangweizhong/p/5713874.html

2.https://blog.csdn.net/ctwy291314/article/details/83147194

快速掌握RabbitMQ(二)——四种Exchange介绍及代码演示的更多相关文章

  1. RabbitMQ的四种ExChange

    在message到达Exchange后,Exchange会根据route规则进入对应的Queue中,message可能进入一个Queue也可能进入对应多个Queue,至于进入哪个Queue或者是说哪个 ...

  2. RabbitMQ 四种Exchange

    AMQP协议中的核心思想就是生产者和消费者隔离,生产者从不直接将消息发送给队列.生产者通常不知道是否一个消息会被发送到队列中,只是将消息发送到一个交换机.先由Exchange来接收,然后Exchang ...

  3. Netty之WebSocket和四种IO介绍

    Netty简介 一.什么是netty? 高性能 事件驱动 异步非堵塞 基于NIO的客户端,服务器端编程框架 稳定性和伸缩性 二.Netty的使用场景 高性能领域   多线程并发领域   异步通信领域 ...

  4. mysql进阶(六)模糊查询的四种用法介绍

    mysql中模糊查询的四种用法介绍 这篇文章主要介绍了mysql中模糊查询的四种用法,需要的朋友可以参考下. 下面介绍mysql中模糊查询的四种用法: 1 %: 表示任意0个或多个字符.可匹配任意类型 ...

  5. 快速理解VirtualBox的四种网络连接方式

    VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...

  6. 单元测试_JUnit常用单元测试注解介绍及代码演示

    JUnit常用单元测试注解介绍及代码演示   by:授客 QQ:1033553122 1. 测试环境 1 2. 基础概念 1 3. 常用Annotation 1 4. 运行环境配置 3 maven配置 ...

  7. RabbitMQ ——四种ExChange及完整示例

    RabbitMQ常用的Exchange Type有fanout.direct.topic.headers这四种,下面分别进行介绍. 这四种类的exchange分别有以下一些属性,分别是: name:名 ...

  8. mysql中模糊查询的四种用法介绍

    下面介绍mysql中模糊查询的四种用法: 1,%:表示任意0个或多个字符.可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示. 比如 SELECT * FROM [user] ...

  9. php 冒泡 快速 选择 插入算法 四种基本算法

    php四种基础算法:冒泡,选择,插入和快速排序法 来源:PHP100中文网 | 时间:2013-10-29 15:24:57 | 阅读数:120854 [导读] 许多人都说 算法是程序的核心,一个程序 ...

随机推荐

  1. C++值传递、引用传递和指针传递

    #include<iostream> using namespace std; //值传递 void change1(int n){ cout<<"值传递--函数操作 ...

  2. mysql启动提示mysql.host 不存在,启动失败的解决方法

    图示: 日志: 190625 10:48:42 InnoDB: Started; log sequence number 0 130207190625 10:48:42 [ERROR] Fatal e ...

  3. java后台验证码的生成

    前台代码: <tr> <td>验证码</td> <td><input name="checkCode" type=" ...

  4. 身份证号正则校验(js校验+JAVA校验)

    js校验身份证号[15位和18位] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...

  5. javaEE(13)_jdbc框架

    一.使用模板方法设计模式简化开发 模板方法设计模式,执行一个程序有很多步骤,将每次都要执行的共有的提取出来放到一个抽象父类中,变化的部分通过让子类传递参数过来或将这部分抽象为抽象方法让子类通过继承的方 ...

  6. 连接器前置挂载U盾

    连接器前置挂载U盾 1. 宿主机配置及其信息 虚拟化软件版本 主机名 宿主机IP 账号及其密码 WorkStation windows idca- vm01 172.16.6.30 * Qemu-kv ...

  7. golang 实现冒泡排序

    package main import ( "fmt" ) func main(){ a := [...] int{2,5,9,6,8} fmt.Println(a) num := ...

  8. UITextView 实现placeholder

    1.在创建textView的时候,赋值其文本属性 即 textView.text = @"内容": 2.在开始编辑的代理方法中进行如下操作 - (void)textViewDidB ...

  9. nrf52810学习笔记——三

    在开发nRF52系列的蓝牙方案的时候,会用到IDE.SDK.softdevice.nrfgoStudio等开发软件,这里做一个小小的总结. 首先,下载SDK,里面有适合keil4号iar7(iar8也 ...

  10. ubuntu介绍以及使用

    Ubuntu(友帮拓.优般图.乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于Debian GNU/Linux,支持x86.amd64(即x64)和ppc架构,由全球 ...