建立
使用官方的RabbitMQ docker
容器并通过运行启动队列
docker run -d --hostname my-rabbit --name some-rabbit -p 8080:15672 -p 5672:5672 rabbitmq:3-management
在发布者拥有队列的那一刻,通过启动它,将创建队列并使用他们自己的路由键定义两个主题。
发布者
using System;
using RabbitMQ.Client;
using System.Text;
using System.Threading;
namespace publisher
{
class Program
{
static void Main(string[] args)
{
Random rnd = new Random();
Console.WriteLine("Starting publisher!");
var factory = setupConnection();
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel()){
//队列
//在声明队列时,请记住考虑队列应具有的持久性以及是否应该是排他性队列(Exclusive Queue)。
// channel.QueueDeclare(queue: "pingpong",
// durable: false,
// exclusive: false,
// autoDelete: false,
// arguments: null);
channel.QueueDeclare(queue: "pingpongA",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.QueueDeclare(queue: "pingpongB",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
//Topic
channel.ExchangeDeclare(exchange: "pingpong",
type: "topic");
//使用Topic绑定特定队列并定义路由键
channel.QueueBind(queue: "pingpongA",
exchange: "pingpong",
routingKey: "topicA");
channel.QueueBind(queue: "pingpongB",
exchange: "pingpong",
routingKey: "topicB");
while (true)
{
string messageTopicA = Guid.NewGuid() + ", Hello TopicA!, " + DateTime.Now;
var bodyTopicA = Encoding.UTF8.GetBytes(messageTopicA);
string messageTopicB = Guid.NewGuid() + ", Hello TopicB!, " + DateTime.Now;
var bodyTopicB = Encoding.UTF8.GetBytes(messageTopicB);
try
{
//队列
//对于每个队列,请考虑使用路由键来处理请求/响应模式。 这将使用相同的topic,但在该topic上创建特定的路由。
// channel.BasicPublish(exchange: "",
// routingKey: "sent",
// basicProperties: null,
// body: body);
//考虑做发布者确认,这将引入开销,因为需要维护事务,有关详细信息,请参阅https://www.rabbitmq.com/confirms.html
//Topic
channel.BasicPublish(exchange: "pingpong",
routingKey: "topicA",
basicProperties: null,
body: bodyTopicA);
channel.BasicPublish(exchange: "pingpong",
routingKey: "topicB",
basicProperties: null,
body: bodyTopicB);
//生成一些随机行为
Console.WriteLine(" [x] Sent {0}", messageTopicA);
Console.WriteLine(" [y] Sent {0}", messageTopicB);
Thread.Sleep(rnd.Next(2000, 6000));
}
//捕获生成的异常,这是在网络或rabbitmq更改下抛出的。 该异常包含一条消息,有时可以解释抛出的异常类型。
catch (RabbitMQ.Client.Exceptions.AlreadyClosedException)
{
Console.WriteLine("Connection is down, trying to reconnect.");
}
}
}
}
static ConnectionFactory setupConnection()
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
//设置恢复选项
factory.AutomaticRecoveryEnabled = true;
factory.TopologyRecoveryEnabled = true;
//来自标准文档
factory.RequestedHeartbeat = 60;
//随机化连接间隔,因此多个连接不会尝试同时重新连接。
Random rnd = new Random();
factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(rnd.Next(15, 45));
return factory;
}
}
}
消费者
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace consumer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Consumer!");
var factory = setupConnection();
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
//队列
//声明确定队列存在,考虑发布者或消费者是否应该创建队列
// channel.QueueDeclare(queue: "pingpongA",
// durable: true,
// exclusive: false,
// autoDelete: false,
// arguments: null);
// channel.QueueDeclare(queue: "pingpongB",
// durable: false,
// exclusive: false,
// autoDelete: false,
// arguments: null);
// var consumer = new EventingBasicConsumer(channel);
// consumer.Received += (model, ea) =>
// {
// var body = ea.Body;
// var message = Encoding.UTF8.GetString(body);
// Console.WriteLine(" [x] Received {0}", message);
// };
//记住考虑自动确认是否应该为真,首选是完全处理请求然后确认。
// channel.BasicConsume(queue: "pingpong",
// autoAck: true,
// consumer: consumer);
//Topic
channel.ExchangeDeclare(exchange: "pingpong", type: "topic");
//使用Topic绑定特定队列并定义路由键
// channel.QueueBind(queue: "pingpongA",
// exchange: "pingpong",
// routingKey: "topicA");
// channel.QueueBind(queue: "pingpongB",
// exchange: "pingpong",
// routingKey: "topicB");
//生成消费者
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'",
routingKey,
message);
channel.BasicAck(ea.DeliveryTag, false);
};
//启动两个不同队列的消费者
channel.BasicConsume(queue: "pingpongA",
autoAck: false,
consumer: consumer);
channel.BasicConsume(queue: "pingpongB",
autoAck: false,
consumer: consumer);
Console.ReadLine();
}
}
static ConnectionFactory setupConnection()
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
//AutomaticRecoveryEnabled 断线重连,也就是如果当前的连接断开了,将会尝试重连
//TopologyRecoveryEnabled 重连后恢复当前的工作进程,比如channel、queue、发布的消息进度等 //设置重新声明交换器,队列等信息。
//设置恢复选项
factory.AutomaticRecoveryEnabled = true;
factory.TopologyRecoveryEnabled = true;
//来自标准文档
factory.RequestedHeartbeat = 60;
//随机化连接间隔,因此多个连接不会尝试同时重新连接。
Random rnd = new Random();
//设置每15-45s ,重试一次
factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(rnd.Next(15, 45));
return factory;
}
}
}