【开发笔记系列(四)】MQ消息队列,发布与订阅
VS,项目框架.NET Core 3.1
导入Nuget包,RabbitMQ.client

下面讲解下Fanout、Direct、Topic的区别
Fanout
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
Direct
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
Topic
前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:
- routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
- binding key与routing key一样也是句点号“. ”分隔的字符串
- binding key中可以存在两种特殊字符“”与“#”,用于做模糊匹配,其中“”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
MQ工具类:
public class RabbitMq
{
private static IConfiguration Configuration;
private readonly ConnectionFactory _factory;
public static void Configure(IConfiguration configuration)
{
Configuration = configuration;
}
public RabbitMq()
{
_factory = new ConnectionFactory() { HostName = Configuration.GetSection("RabbitMqSetting:HostName").Value, UserName = Configuration.GetSection("RabbitMqSetting:UserName").Value, Password = Configuration.GetSection("RabbitMqSetting:Password").Value, VirtualHost = Configuration.GetSection("RabbitMqSetting:VirtualHost").Value, Port = int.Parse(Configuration.GetSection("RabbitMqSetting:Port").Value) };
}
public bool QueueBind(string queuename, string exchange, string routekey)
{
using (var connection = _factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: queuename,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.QueueBind(queuename, exchange, routekey);
Console.WriteLine($"{queuename} declared. ");
return true;
}
}
}
public bool ExchangeSendTopic(string exchange, string routingKey, string msg)
{
using (var connection = _factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange, ExchangeType.Topic, true, false);
string message = $"{msg}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: exchange,
routingKey: routingKey,
basicProperties: null,
body: body);
Console.WriteLine($"Sent {exchange} {msg}");
return true;
}
}
}
public bool ExchangeSendFanout(string exchange, string routingKey, string msg)
{
using (var connection = _factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange, ExchangeType.Fanout, true, false);
string message = $"{msg}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: exchange,
routingKey: routingKey,
basicProperties: null,
body: body);
Console.WriteLine($"Sent {exchange} {msg}");
return true;
}
}
}
public void QueueReceive(string queuename)
{
var connection = _factory.CreateConnection();
var channel = connection.CreateModel();
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);
};
channel.BasicConsume(queue: queuename,
autoAck: true,
consumer: consumer);
}
}
appsettings配置文件中:
"RabbitMqSetting": {
"HostName": "192.168.xx.xxx",
"UserName": "name",
"Password": "pass123",
"Port": "56720",
"VirtualHost": "System"
},
创建临时队列
String queueName = mq.QueueReceive(system);
MQ后端管理页面先创建一个虚拟机。

在创建完虚拟机后,在代码接口端调用MQ,会自动生成该代码中设置的交换机和消息队列
空字符串表示默认或无名称交换机:消息能路由发送到队列中其实 是由 routingKey(bindingkey)绑定 key 指定的,如果它存在的话。 那么这种情况下,MQ会走默认的交换机(AMQP default)

生产者、消费者这个关键key(Routing key)
以上是创建虚拟机、发布信息队列
接下来是订阅、消费信息
//调用绑定
Mq.QueueBind(QueueName, ExchangeName, RoutingKey);
public bool QueueBind(string queuename, string exchange, string routekey)
{
using (var connection = _factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
string name=channel.QueueDeclare().QueueName.Split(".")[1];//获取随机队列
channel.QueueDeclare(queue: name,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.QueueBind(name, exchange, routekey);
Console.WriteLine($"{name} declared. ");
QueueReceive(name);
return true;
}
}
}
public void QueueReceive(string queuename)
{
var connection = _factory.CreateConnection();
var channel = connection.CreateModel();
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);
};
channel.BasicConsume(queue: queuename,
autoAck: true,
consumer: consumer);
}
此时定义好订阅通道,生产者消费者都会通过指定交换机中的队列获取推送信息

控制台输出:


浙公网安备 33010602011771号