先決條件
本教程假定 RabbitMQ 已經安裝,並運行在localhost
標准端口(5672)。如果你使用不同的主機、端口或證書,則需要調整連接設置。從哪里獲得幫助
如果您在閱讀本教程時遇到困難,可以通過郵件列表 聯系我們。
介紹
RabbitMQ 是一個消息中間件:它接收並轉發消息。您可以把它想象為一個郵局:當您把需要寄出的郵件投遞到郵箱,郵差最終會把郵件送給您的收件人。在這個比喻中,RabbitMQ 就是一個郵箱,也可以理解成郵局和郵遞員。
RabbitMQ 和郵局的主要區別在於它不處理紙張,而是接收、存儲和轉發二進制數據塊 - 消息。
RabbitMQ 和消息傳遞通常使用一些術語。
生產 的意思無非就是發送。發送消息的程序就是一個 生產者:
隊列 就是 RabbitMQ 內部“郵箱”的名稱。雖然消息流經 RabbitMQ 和您的應用程序,但它們只能存儲在 隊列 中。隊列 只受主機的內存和磁盤的限制,它本質上就是一個很大的消息緩沖區。多個 生產者 可以發送消息到一個隊列,並且多個 消費者 可以嘗試從一個 隊列 接收數據。這就是我們代表隊列的方式:
消費 與接收有相似的含義,等待接收消息的程序就是一個 消費者:
注意:生產者、消費者和中間件不是必須部署在同一主機上,實際上在大多數應用程序中它們也不是這樣的。
"Hello World"
使用 .NET / C#Client
在教程的這一部分,我們將用 C# 編寫兩個程序:一個發送單條消息的生產者,以及接收消息並將其打印出來的消費者。我們將忽略 .NET 客戶端 API 中的一些細節,專注於更簡單的開始。這是一個消息傳遞的“Hello World”。
在下圖中,P
是我們的生產者,C
是我們的消費者。中間的盒子是隊列 - RabbitMQ 代表消費者保存的消息緩沖區。
.NET 客戶端庫
RabbitMQ 支持多種協議,本教程使用
AMQP 0-9-1
,它是一種開放的、通用的消息傳遞協議。RabbitMQ 提供了一些針對不同 語言環境 的客戶端,我們將使用 RabbitMQ 提供的 .NET 客戶端。客戶端支持 .NET Core 以及 .NET Framework 4.5.1+。本教程將使用 .NET Core,因此您需要確保客戶端已 安裝 並且路徑添加到
PATH
系統變量。您也可以使用 .NET Framework 來完成本教程,但設置步驟會有所不同。
RabbitMQ .NET 客戶端 5.0 及更高版本通過 nuget 發布。
本教程假定您在 Windows 上使用 PowerShell。在 MacOS 和 Linux 上,幾乎所有 shell 也都可以正常工作。
安裝
首先讓我們驗證您在PATH
系統變量是否有 .NET Core 工具鏈:
dotnet --help
應該產生幫助信息。
現在,讓我們生成兩個項目,一個用於發布者,另一個用於消費者:
dotnet new console --name Send
mv Send/Program.cs Send/Send.cs
dotnet new console --name Receive
mv Receive/Program.cs Receive/Receive.cs
這將創建兩個名為Send
和Receive
的新目錄。
然后,我們添加客戶端依賴項。
cd Send
dotnet add package RabbitMQ.Client
dotnet restore
cd ../Receive
dotnet add package RabbitMQ.Client
dotnet restore
我們已經建立了 .NET 項目,現在我們可以編寫一些代碼。
發送
我們將調用我們的消息發布者(發送者)Send.cs
和我們的消息消費者(接收者)Receive.cs
。發布者將連接到 RabbitMQ,發送一條消息,然后退出。
在 Send.cs 中,我們需要使用一些命名空間:
using System;
using RabbitMQ.Client;
using System.Text;
設置類:
class Send
{
public static void Main()
{
...
}
}
然后,我們可以創建一個連接,連接到服務器:
class Send
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
...
}
}
}
}
該連接抽象了套接字連接,並為我們處理協議版本的協商和身份驗證等。在這里,我們連接的是本地機器上的代理, 因此是localhost
。如果我們想連接到其他機器上的代理,我們只需在此指定其名稱或 IP 地址。
接下來,我們創建一個通道,該 API 的主要功能是把獲得信息保存起來。
想要發送消息,我們必須為需要發送的消息聲明一個隊列,然后我們就可以把消息發布到隊列中:
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();
}
}
聲明隊列是 冪等 的 - 只有當它不存在時才會被創建。消息內容是一個字節數組,所以您可以用喜歡的任意方式編碼。
當上面的代碼完成運行時,通道和連接將被釋放。這就是我們的發布者。
(Send.cs 源碼)
發送不起作用!
如果這是您第一次使用 RabbitMQ,並且您沒有看到“已發送”消息,那么您可能會撓着頭想知道錯誤出在什么地方。也許是代理程序啟動時沒有足夠的可用磁盤空間(默認情況下,它至少需要50 MB空閑空間),因此拒絕接收消息。
必要時檢查代理程序日志文件來確認和減少限制。配置文件 文檔 將告訴您如何設置disk_free_limit
。
接收
至於消費者,它是把消息從 RabbitMQ 拉取過來。因此,與發布消息的發布者不同,我們會保持消費者持續不斷地運行,監聽消息並將其打印出來。
代碼(在 Receive.cs 中)具有與Send
差不多一樣的using
聲明:
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
設置與發布者相同;我們開啟一個連接和一個通道,並聲明我們將要使用的隊列。請注意,這需要與Send
發布到的隊列相匹配。
class Receive
{
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);
...
}
}
}
}
請注意,我們在這里也聲明了隊列。因為我們可能會在發布者之前啟動消費者,所以我們希望在我們嘗試從它中消費消息之前確保隊列已存在。
我們即將告訴服務器將隊列中的消息傳遞給我們。由於它會異步推送消息,因此我們提供了一個回調。這就是EventingBasicConsumer.Received
事件處理程序所做的事情。
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
class Receive
{
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);
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();
}
}
}
(Receive.cs 源碼)
組合在一起
打開兩個終端。
運行消費者:
cd Receive
dotnet run
運行生產者:
cd Send
dotnet run
消費者將打印它通過 RabbitMQ 從發布者處獲得的消息。消費者將繼續運行、等待新消息(按Ctrl-C
將其停止),可以嘗試從開啟另一個終端運行發布者。
接下來可以跳轉到 教程[2],構建一個簡單的工作隊列。
寫在最后
本文翻譯自 RabbitMQ 官方教程 C# 版本。如本文介紹內容與官方有所出入,請以官方最新內容為准。水平有限,翻譯的不好請見諒,如有翻譯錯誤還請指正。
- 原文鏈接:RabbitMQ tutorial - "Hello World!"
- 實驗環境:RabbitMQ 3.7.4 、.NET Core 2.1.3、Visual Studio Code
- 最后更新:2018-03-13