RabbitMQ学习笔记(一) Hello World

RabbitMQ是做什么的?

RabbitMQ可以类比现实生活中的邮政服务。

现实中邮件服务处理的是邮件,发件人写好信件投入邮箱,邮递员收取信件存入邮局,邮局根据信件地址,分配邮递员投递信件到指定地点。

RabbitMQ与邮政服务的主要区别是RabbitMQ处理的是消息(二进制数据块), 即消息的接收、存储、分发。

 

RabbitMQ中的主要概念

消息生产者(producer)#

发送消息的程序

消息消费者(Consumer)#

等待接收消息的程序

消息队列#

RabbitMQ中的消息队列,就相当于邮政服务中的邮箱,所有通过RabbitMQ和你的应用程序发送接收的消息都存储在消息队列中,它是一个巨大的消息缓存,它的大小仅受服务器内存和硬盘空间的限制。

多个消息生产者可以通过同一个消息队列发送消息,多个消息消费者也可以通过同一个消息队列接收消息。

消息的生产者、消费者、消息队列不需要一定放置在同一个服务器中,现实中的大部分应用场景也不会允许他们放置在同一服务器中

 

第一个Hello World程序

 

这里我们创建2个控制台程序,一个负责发送简单的 Hello World消息,一个负责输出接收到的消息,并在控制台打印。

 

流程图如下,P为生产者,C为消费者,中间的红色块是消息队列

创建程序#

使用.NET Core的命令行工具,创建2个控制台程序,一个命名为Send, 另外一个命名为Receive。

1
2
3
dotnet new console –name Send
 
dotnet new console –name Receive

 

安装RabbitMQ客户端程序集#

使用.NET Core的命令行工具,分别为2个控制台程序添加RabbitMQ客户端程序集

dotnet add package RabbitMQ.Client

dotnet restore

 

编写消息发送程序#

首先引入一些命名空间

1
2
3
4
5
using System;
 
using RabbitMQ.Client;
 
using System.Text;

 

然后在修改Main方法添加如下代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var factory = new ConnectionFactory() { HostName = "localhost" };
 
        using (var connection = factory.CreateConnection())
 
        {
 
            using (var channel = connection.CreateModel())
 
            {
 
                
 
            }
 
        }

 

connection对象抽象出了一个Socket连接,并负责RabbitMQ所使用的协议版本的验证和协商。

这里连接的是本地的RabbitMQ实例,所以使用的localhost作为主机名,如果需要连接其他服务器的RabbitMQ实例,只需要将主机名变更为对应服务器的ip地址即可。

 

然后我们需要创建一个channel对象,大部分的消息处理有关的api都是在channel对象中。

接下来,为了发送消息,我们需要创建一个消息队列,然后向这个消息队列中发布消息。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
 
using RabbitMQ.Client;
 
using System.Text;
 
  
 
class Send
 
{
 
    public static void Main()
 
    {
 
        var factory = new ConnectionFactory() { HostName = "localhost" };
 
        using(var connection = factory.CreateConnection())
 
        using(var channel = connection.CreateModel())
 
        {
 
            channel.QueueDeclare(queue: "hello",
 
                                 durable: false,
 
                                 exclusive: false,
 
                                 autoDelete: false,
 
                                 arguments: null);
 
  
 
            string message = "Hello World!";
 
            var body = Encoding.UTF8.GetBytes(message);
 
  
 
            channel.BasicPublish(exchange: "",
 
                                 routingKey: "hello",
 
                                 basicProperties: null,
 
                                 body: body);
 
            Console.WriteLine(" [x] Sent {0}", message);
 
        }
 
  
 
        Console.WriteLine(" Press [enter] to exit.");
 
        Console.ReadLine();
 
    }
 
}

 

Channel对象的QueueDeclare方法是用来声明一个消息队列的,这个方法是等幂的,即只要当该消息队列不存在的时候才创建他,如果已经存在,就直接返回之前创建的对象。

RabbitMQ中传递的消息是二进制数据,所以需要将传递的文本转换成二进制数据。

这样消息发送程序就完成了。

 

编写接收消息程序#

前面我们做的发送程序运行一次只发送一条消息,与发送程序不同,接收消息程序需要监听接收到的所有消息,并打印。

首先我们引入需要使用的命名空间

1
2
3
4
5
6
7
using RabbitMQ.Client;
 
using RabbitMQ.Client.Events;
 
using System;
 
using System.Text;

 

初始的设置代码和发送程序一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void Main()
 
    {
 
        var factory = new ConnectionFactory() { HostName = "localhost" };
 
        using (var connection = factory.CreateConnection())
 
        {
 
            using (var channel = connection.CreateModel())
 
            {
 
                channel.QueueDeclare(queue: "hello",
 
                                     durable: false,
 
                                     exclusive: false,
 
                                     autoDelete: false,
 
                                     arguments: null);
 
                
 
            }
 
        }
 
    }

 

这里还要重复声明一次消息队列的原因是,你不能保证在消息接收程序启动时,消息队列一定存在(即消息接收程序的启动早于发送消息程序)。

 

由于消息的推送是异步的,所以这里我们需要使用事件来捕捉消息,并打印在控制台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
var factory = new ConnectionFactory() { HostName = "localhost" };
 
        using(var connection = factory.CreateConnection())
 
        using(var channel = connection.CreateModel())
 
        {
 
            channel.QueueDeclare(queue: "hello",
 
                                 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: "hello",
 
                                 autoAck: true,
 
                                 consumer: consumer);
 
  
 
            Console.WriteLine(" Press [enter] to exit.");
 
            Console.ReadLine();
 
        }

 

运行程序#

在消息发送程序和消息接收程序目录下,使用.NET Core命令行工具启动2个项目

dotnet run
posted @   LamondLu  阅读(471)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示
主题色彩