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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?