RabbitMQ 使用记录
RabbitMQ交换机类型
RabbitMQ共有四种交换机类型:
- Direct Exchange:直连交换机,根据Routing Key(路由键)进行投递到不同队列。
- Fanout Exchange:扇形交换机,采用广播模式,根据绑定的交换机,路由到与之对应的所有队列。
- Topic Exchange:主题交换机,对路由键进行模式匹配后进行投递,符号#表示一个或多个词,*表示一个词。
- Header Exchange:头交换机,不处理路由键。而是根据发送的消息内容中的headers属性进行匹配。
Direct Exchange
单个绑定,一个路由键对应一个队列。如下所示:
多个绑定,一个路由键对应多个队列,则消息会分别投递到两个队列中,如下所示:
Fanout Exchange
扇形交换机,采用广播模式,根据绑定的交换机,路由到与之对应的所有队列。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。
Topic Exchange
主题交换机,对路由键进行模式匹配后进行投递,符号#表示一个或多个词,*表示一个词。因此“abc.#”能够匹配到“abc.def.ghi”,但是“abc.*” 只会匹配到“abc.def”。如下所示:
Header Exchange
头交换机,不处理路由键。而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到RabbitMQ时会取到该消息的headers与Exchange绑定时指定的键值对进行匹配;如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers属性是一个键值对,可以是Hashtable,键值对的值可以是任何类型。而fanout,direct,topic 的路由键都需要要字符串形式的。
匹配规则x-match有下列两种类型:
x-match = all :表示所有的键值对都匹配才能接受到消息
x-match = any :表示只要有键值对匹配就能接受到消息
消息头交换机,如下图所示:
消息发送方 要设置好交换机和路由键 ,接收方把交换机和队列通过路由键 进行绑定,这样就可以根据不同的路由键进行发送接收
发送端代码
// See https://aka.ms/new-console-template for more information using RabbitMQ.Client; using System.Text; Console.WriteLine("Hello, World!"); RabbitMQSend.Send(args); public static class RabbitMQSend { public static void Send(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost", UserName = "admin", Password = "1234567891000", Port = 5672 }; using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { // 设置交换机 type为交换机的类型 这里设为直连交换机 channel.ExchangeDeclare(exchange: "direct_exc", type: "direct"); // 消息持久化 成持久化的 durable 要设置 True var properties = channel.CreateBasicProperties(); properties.Persistent = true; string message = "Hello World!"; var body = Encoding.UTF8.GetBytes(message); while (true) { Task.Delay(500).GetAwaiter().GetResult(); foreach (var item in args) { // 设置消息要发送的交换机和 routingKey路由键,根据路由键发送到具体的队列中 channel.BasicPublish(exchange: "direct_exc", routingKey: item, basicProperties: properties, body: body); } } } } } }
接收端代码
// See https://aka.ms/new-console-template for more information using RabbitMQ.Client; using RabbitMQ.Client.Events; RabbitMQReceive.Receive(args); Console.WriteLine("Hello, World!"); public static class RabbitMQReceive { public static void Receive(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost", UserName = "admin", Password = "123456", Port = 5672 }; using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { // 设置交换机,跟发送端一致 channel.ExchangeDeclare(exchange: "direct_exc", type: "direct"); // 设置队列 可使用下一行的注释代码来设置一个默认的队列 var queueName = channel.QueueDeclare().QueueName; channel.QueueDeclare(queue: "direct_ques",// 队列名称 durable: true,// 消息持久化,当设置了未持久化,就要重新设置 Queue exclusive: false,//设置队列是否排他,排他则只能首次声明它的连接可用 autoDelete: true,// 当队列有客户端连接之后,所有客户端断开连接后删除队列 arguments: null); // 绑定交换级与队列 channel.QueueBind(queue: "direct_ques",// 要绑定的队列名称 exchange: "direct_exc", // 要绑定的交换机 routingKey: "error"); // 绑定的路由键 // 公平调度 自动应答autoAck要设置为false,不然没效果. prefetchCount设置接收端处理的请求数,这里设置处理一条,可设置为15,表示同时处理15条 channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false); // 接收消息事件 var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body.ToArray(); var message = System.Text.Encoding.UTF8.GetString(body); Console.WriteLine(" [x] Received {0}", message); // 手动确认,要把 autoAck 设置为false的 channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); }; channel.BasicConsume(queue: "direct_ques", autoAck: false,// 进行消息自动确认 consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } }