RabbitMQ c#

一简介

1 MQ

(1) MQ简介

消息队列(Message Queue),是一种跨进程、异步的通信机制,用于上下游传递消息。由消息系统来确保消息的可靠传递

(2) 产生消息队列的原因

1> 不同进程(process)之间传递消息时,两个进程之间耦合程度过高,改动一个进程,引发必须修改另一个进程,为了隔离这两个进程,在两进程间抽离出一层(一个模块),所有两进程之间传递的消息,都必须通过消息队列来传递,单独修改某一个进程,不会影响另一个
2> 不同进程(process)之间传递消息时,为了实现标准化,将消息的格式规范化了,并且,某一个进程接受的消息太多,一下子无法处理完,并且也有先后顺序,必须对收到的消息进行排队,因此诞生了事实上的消息队列;

2 RabbitMQ

(1) RabbitMQ 简介

RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。

(2) RabbitMQ服务支持的操作系统

linux, windows, macox

(3) RabbitMQ支持的开发语言

java, python. ruby, c#, c/c++, node.js, go 等

3 开发语言

Erlang

4 协议AMOP

AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等

二 RabbitMQ 模式介绍

1 简单模式

在这里插入图片描述
P:消息的生产者
C:消息的消费者
红色:队列
生产者将消息发送到队列,消费者从队列中获取消息

send code

static void mq_simple_mode_send_fun()
{
 var host = "127.0.0.1";
 var port = 5672;
 var username = "readsense";
 var password = "readface";
 IConnection conn = null;
 IModel channel = null;
 try
 {
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    string queueName = "SimpleQueue";
    channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
    string msg = "HelloWorld";
    channel.BasicPublish("", queueName, null, Encoding.UTF8.GetBytes(msg));
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

recv code

static void mq_simple_mode_recv_fun()
{
 IConnection conn = null;
 IModel channel = null;
 try
 {
  var host = "127.0.0.1";
  var port = 5672;
  var username = "readsense";
  var password = "readface";
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    string queueName = "SimpleQueue";
    channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
    var consumer = new QueueingBasicConsumer(channel);
    // noAck: true 自动回复
    // noAck: false 手动回复
    // 现在BasicConsume函数 noAck 参数设置为手动回复
    channel.BasicConsume(queueName, false, consumer);
    while (true)
    {
     var ea = consumer.Queue.Dequeue();
     var body = ea.Body;
     var message = Encoding.UTF8.GetString(body);
     Console.WriteLine("已接收:{0}", message);
     // 回复
     channel.BasicAck(ea.DeliveryTag, false);
    }
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

2 work 模式

在这里插入图片描述
备注: work 模式代码 和 简单模式代码基本一致, 只需要增加公平分发的相关几行代码.具体如下:

特点
1 当有多个消费者时, 一个消息,只能有一个消费者获取获得
2 轮询分发 消费者1 和 消费者2 获取的消息数是相同的
3 公平分发 通过忙闲控制分发

注意点:
如果轮询分发, 打一个消费者比较忙时, 任然轮询是不合理的, 因此我们采用公平分发
1 我们使用basicQos( prefetchCount = 1)方法,来限制RabbitMQ只发不超过1条的消息给同一个消费者。当消息处理完毕后,有了反馈,才会进行第二次发送。
2 关闭自动应答,改为手动应答。

// 同一时刻服务器只会发一条消息给消费者
// 消费者代码增加  channel.basicQos(1);

// 现在BasicConsume函数 noAck 参数设置为手动回复
channel.BasicConsume(queueName, false, consumer);

// 手动确认回复
 channel.BasicAck(ea.DeliveryTag, false);

3 订阅模式

exchange 类型: fanout
功能:一个生产者发送的消息会被多个消费者获取。一个生产者、一个交换机、多个队列、多个消费者
生产者:可以将消息发送到队列或者是交换机。
消费者:只能从队列中获取消息。
备注:
1 如果消息发送到没有队列绑定的交换机上,那么消息将丢失。
2 交换机不能存储消息,消息存储在队列中
3 消费者队列可以有多个消费者实例,只有其中一个消费者实例会消费
在这里插入图片描述
在这里插入图片描述

send code

// 订阅模式
static void mq_pubsub_mode_send_fun()
{
 var host = "127.0.0.1";
 var port = 5672;
 var username = "readsense";
 var password = "readface";
 var exchange_name = "test_exchange_fanout";
 IConnection conn = null;
 IModel channel = null;
 try
 {
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    channel.ExchangeDeclare(exchange_name, "fanout");
    string msg = "HelloWorld";
    channel.BasicPublish(exchange_name, "", null, Encoding.UTF8.GetBytes(msg));
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

recv code

// 订阅模式
static void mq_pubsub_mode_recv_fun()
{
 IConnection conn = null;
 IModel channel = null;
 try
 {
  var host = "127.0.0.1";
  var port = 5672;
  var username = "readsense";
  var password = "readface";
  var exchange_name = "test_exchange_fanout";
  var queueName = "test_queue_sub_1";
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
    channel.QueueBind(queueName, exchange_name, "");
    channel.BasicQos(0, 1, false);
    var consumer = new QueueingBasicConsumer(channel);
    channel.BasicConsume(queueName, false, consumer);
    while (true)
    {
     var ea = consumer.Queue.Dequeue();
     var body = ea.Body;
     var message = Encoding.UTF8.GetString(body);
     Console.WriteLine("已接收:{0}", message);
     channel.BasicAck(ea.DeliveryTag, false);
    }
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

4 路由模式

exchange 类型: direct
生产者发送消息到交换机并且要指定路由key,消费者将队列绑定到交换机时需要指定路由key
在这里插入图片描述
send code

// 路由模式
static void mq_directexchange_mode_send_fun()
{
 var host = "127.0.0.1";
 var port = 5672;
 var username = "readsense";
 var password = "readface";
 var exchange_name = "test_exchange_direct";
 IConnection conn = null;
 IModel channel = null;
 try
 {
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    channel.ExchangeDeclare(exchange_name, "direct");
    for (int loop = 0; loop < 100; loop++)
    {
     Thread.Sleep(1000);
     if (loop % 2 == 0)
     {
      string msg = "update info";
      channel.BasicPublish(exchange_name, "update", null, Encoding.UTF8.GetBytes(msg));
     }
     else
     {
      string msg = "delete info";
      channel.BasicPublish(exchange_name, "delete", null, Encoding.UTF8.GetBytes(msg));
     }
    }
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

recv code

// 路由模式
static void Mqtt_DirectExchange_Mode_Recv_Fun()
{
 IConnection conn = null;
 IModel channel = null;
 try
 {
  var host = "127.0.0.1";
  var port = 5672;
  var username = "readsense";
  var password = "readface";
  var exchange_name = "test_exchange_direct";
  var queueName = "test_queue_direct_1";
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    channel.ExchangeDeclare(exchange_name, "direct");
    channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
    channel.QueueBind(queueName, exchange_name, "delete");
    // channel.QueueBind(queueName, exchange_name, "delete");
    channel.BasicQos(0, 1, false);
    var consumer = new QueueingBasicConsumer(channel);
    channel.BasicConsume(queueName, false, consumer);
    while (true)
    {
     var ea = consumer.Queue.Dequeue();
     var body = ea.Body;
     var message = Encoding.UTF8.GetString(body);
     Console.WriteLine("已接收:{0}", message);
     channel.BasicAck(ea.DeliveryTag, false);
    }
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

5 主题模式(通配符模式)

Topic Exchange - 将路由键和某模式进行匹配, 此时队列需要绑定某个模式上, 符号"#“匹配一个或多个字符,”*"匹配一个字符.
在这里插入图片描述
send code

// topic模式
static void mq_topic_mode_send_fun()
{
 var host = "127.0.0.1";
 var port = 5672;
 var username = "readsense";
 var password = "readface";
 var exchange_name = "test_exchange_topic";
 IConnection conn = null;
 IModel channel = null;
 try
 {
  ConnectionFactory factory = new ConnectionFactory();
  factory.HostName = host;
  factory.Port = port;
  factory.UserName = username;
  factory.Password = password;
  using (conn = factory.CreateConnection())
  {
   using (channel = conn.CreateModel())
   {
    channel.ExchangeDeclare(exchange_name, "topic");
    for (int loop = 0; loop < 100; loop++)
    {
     Thread.Sleep(1000);
     if (loop % 2 == 0)
     {
      string msg = "update info";
      channel.BasicPublish(exchange_name, "routekey.1", null, Encoding.UTF8.GetBytes(msg));
     }
     else
     {
      string msg = "delete info";
      channel.BasicPublish(exchange_name, "routekey.2", null, Encoding.UTF8.GetBytes(msg));
     }
    }
   }
  }
 }
 catch (Exception ex)
 {
  Console.WriteLine("Exception error:" + ex.Message);
 }
}

recv code

// topic 模式:
        static void mq_topic_mode_recv_fun()
        {
            IConnection conn = null;
            IModel channel = null;
            try
            {
                var host = "127.0.0.1";
                var port = 5672;
                var username = "readsense";
                var password = "readface";
                var exchange_name = "test_exchange_topic";
                var queueName = "test_queue_topic_1";
                ConnectionFactory factory = new ConnectionFactory();
                factory.HostName = host;
                factory.Port = port;
                factory.UserName = username;
                factory.Password = password;
                using (conn = factory.CreateConnection())
                {
                    using (channel = conn.CreateModel())
                    {
                        channel.ExchangeDeclare(exchange_name, "topic");
                        channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
                        channel.QueueBind(queueName, exchange_name, "routekey.#");
                        // channel.QueueBind(queueName, exchange_name, "delete");
                        channel.BasicQos(0, 1, false);
                        var consumer = new QueueingBasicConsumer(channel);
                        channel.BasicConsume(queueName, false, consumer);
                        while (true)
                        {
                            var ea = consumer.Queue.Dequeue();
                            var body = ea.Body;
                            var message = Encoding.UTF8.GetString(body);
                            Console.WriteLine("已接收:{0}", message);
                            channel.BasicAck(ea.DeliveryTag, false);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception error:" + ex.Message);
            }
        }

三 参考文档

1 RabbitMQ参考文档

https://blog.csdn.net/hellozpc/article/details/81436980
备注: rabbitmq 安装可参考上面文档

2 RabbitMQ官网文档

https://www.rabbitmq.com/getstarted.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值