RabbitMQ-简单的生产者-消费者模式

RabbitMQ 是一个消息代理:它接受并转发消息。可以把它看成是一个邮局:当你把你想要邮寄的邮件放在一个邮筒里时,你可以确信信使最终会把邮件送到您的收件人手中。在这里,RabbitMQ 充当了邮筒,邮局,信使的角色。

RabbitMQ 与邮局的主要区别在于它不处理纸张,他所做的仅仅只是接收、转发消息。
下面是RabbitMQ中使用到的几个术语
生产者(P):消息的发送方,一个程序如果发送消息,那么他就是生产者

队列(Queue):队列相当于RabbitMQ里面的一个邮筒,尽管消息流经过RabbitMQ和你的应用程序,但是他们只能被存储在队列中。一个队列只受到主机的内存和硬盘限制,队列在本质上是一个大型的消息缓冲区。大量生产者可以发送消息到一个队列,同时大量消费者也可以尝试从队列中获取数据

消费者(C):消费者有类似接收的含义,一个消费者就是一段主要等待接收消息的程序

需要注意的是,消费者、生产者、代理不一定要在同一台主机上,实际上,在大多数应用中,他们都在同一台主机上,一个应用程序可以既是生产者又是消费者

下面将实际编码,以便了解生产者-消费者模式的概念:

我们将使用C#编写两个程序,一个是生产者,一个是接受消息并打印出来的消费者(笔者使用的环境是Windows 10,VS2022,.net core 6.0)

  • 首先在VS中,创建两个控制台应用程序,一个代表生产者(Send),一个代表消费者(Receive)
    image
  • 然后通过Nuget分别在两个项目中引入RabbitMQ的插件RabbitMQ.Client
  • Send代码
using RabbitMQ.Client;
using System.Text;

//该连接抽象了套接字连接,并为我们处理协议版本协商和认证等事宜
//这里我们连接到本地机器上的 RabbitMQ 节点,因此是 localhost。如果我们想连接到不同机器上的一个节点,我们只需在这里指定它的主机名或 IP 地址。
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
    Console.WriteLine("生产者开始发送消息");
    //声明一个队列,以便我们发送,队列声明是幂等的,只有当它不存在的时候才会被创建
    channel.QueueDeclare(queue: "hello",
                         durable: false,
                         exclusive: false,
                         autoDelete: false,
                         arguments: null);

    for (int i = 0; i < 30; i++)
    {
        string message = $"[{i}]:Hello World!";
        var body = Encoding.UTF8.GetBytes(message);
        //向队列发布一个消息。
        channel.BasicPublish(exchange: "",
                             routingKey: "hello",
                             basicProperties: null,
                             body: body);
        Console.WriteLine($"{DateTime.Now:mm:ss:fff} Send Message: [{message}]");

        Thread.Sleep(100);
    }
}

Console.ReadLine();
  • Receive代码
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;


var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
    Console.WriteLine("消费者开始接收消息");

    //请注意,在这里也声明了队列。因为我们可能会在发布者之前启动消费者,所以我们想在尝试消费队列中的消息之前确保队列存在。
    channel.QueueDeclare(queue: "hello",
                         durable: false,
                         exclusive: false,
                         autoDelete: false,
                         arguments: null);

    //告诉服务器将队列中的消息传递给我们
    var consumer = new EventingBasicConsumer(channel);
    consumer.Received += (send, data) =>
    {
        var body = data.Body.ToArray();
        var message = Encoding.UTF8.GetString(body);
        Console.WriteLine($"{DateTime.Now:mm:ss:fff}  Received: [{message}]");
    };
    channel.BasicConsume(queue: "hello",
                         autoAck: true,
                         consumer: consumer);

    Console.ReadLine();
}

  • 将两个项目编译后运行
    消费者将打印它通过 RabbitMQ 从发布者那里获得的消息,消费者将持续运行,一收到消息就打印出来
    从运行结果来看,生产者发送了30条消息,消费者全部接收到并打印了出来

image

posted @ 2021-09-09 14:12  六月的雪0924  阅读(356)  评论(0)    收藏  举报