原文來自 RabbitMQ 英文官網的教程(1.Introduction),其示例代碼採用了 .NET C# 語言。css
RabbitMQ is a message broker: it accepts and forwards messages. You can think about it as a post office: when you put the mail that you want posting in a post box, you can be sure that Mr. Postman will eventually deliver the mail to your recipient. In this analogy, RabbitMQ is a post box, a post office and a postman.html
RabbitMQ 是這樣一個消息代理:它接收和轉發消息。你能夠把它想像成是一個郵局:當你把一份郵件投遞到信箱時,你能夠確信的是郵遞員先生終究會把郵件遞送給接收者。在這個比喻中,RabbitMQ 扮演了信箱、郵局以及郵遞員這一系列角色。git
The major difference between RabbitMQ and the post office is that it doesn't deal with paper, instead it accepts, stores and forwards binary blobs of data ‒ messages.github
RabbitMQ與郵局最大的不一樣在於它並不處理紙質信件,取而代之的是它接收、儲存以及轉發二進制消息數據。shell
RabbitMQ, and messaging in general, uses some jargon.緩存
RabbitMQ 以及消息傳遞,一般會使用到一些專業術語。服務器
Producing means nothing more than sending. A program that sends messages is a producer :併發
生產者的含義無非就是發送,一個程序在發送消息時它就是生產者:app
A queue is the name for a post box which lives inside RabbitMQ. Although messages flow through RabbitMQ and your applications, they can only be stored inside a queue. A queue is only bound by the host's memory & disk limits, it's essentially a large message buffer. Many producers can send messages that go to one queue, and many consumers can try to receive data from one queue. This is how we represent a queue:ssh
隊列實質上就是 RabbitMQ 內部的「信箱」,做爲消息,儘管自 RabbitMQ 流經應用程序,但它最終只會存儲於隊列中。隊列只會受限於主機內存和磁盤空間,本質上來說它實際上是一個龐大的消息緩存區。多個生產者能夠發送消息到同一個隊列,同時多個消費者也能夠從同一個隊列接收數據。下圖是咱們描繪的一個隊列的模樣:
Consuming has a similar meaning to receiving. A consumer is a program that mostly waits to receive messages:
同理,消費也有着相似接收的含義,消費者就是一個主要用來等待接收消息的程序:
Note that the producer, consumer, and broker do not have to reside on the same host; indeed in most applications they don't.
要注意的是,生產者、消費者,以及代理之間沒必要存在於同一臺主機,事實上大部分應用程序也不會這麼作。
"Hello World"
"起步"
In this part of the tutorial we'll write two programs in C#; a producer that sends a single message, and a consumer that receives messages and prints them out. We'll gloss over some of the detail in the .NET client API, concentrating on this very simple thing just to get started. It's a "Hello World" of messaging.
在教程的當前部分咱們會編寫兩個 C# 程序。做爲生產者會發送一條消息,同時消費者會接收消息並將其打印出來。咱們會忽略 API 當中的一些細節,把精力集中在簡單的事情上從而更好的起步。這是一個「Hello World」的消息。
In the diagram below, "P" is our producer and "C" is our consumer. The box in the middle is a queue - a message buffer that RabbitMQ keeps on behalf of the consumer.
在下圖中,"P" 就是生產者,"C"就是消費者。中間的方形盒子就是隊列,即 RabbitMQ 爲消費者保留的消息緩衝區。
.NET 客戶端庫
RabbitMQ speaks multiple protocols. This tutorial uses AMQP 0-9-1, which is an open, general-purpose protocol for messaging. There are a number of clients for RabbitMQ in many different languages. We'll use the .NET client provided by RabbitMQ.
RabbitMQ 支持多種協議,本教程使用的是 AMQP 0-9-1,它是公開的較爲通用的消息協議。RabbitMQ 支持多種語言的客戶端,在這裏咱們將使用 RabbitMQ 提供的 .NET 客戶端。
The client supports .NET Core as well as .NET Framework 4.5.1+. This tutorial will use RabbitMQ .NET client 5.0 and .NET Core so you will ensure you have it installed and in your PATH.
RabbitMQ 提供的 .NET 客戶端已支持 .NET Core 以及 .NET Framework 4.5.1+,本教程將會使用 RabbitMQ .NET client 5.0 和 .NET Core,因此你須要確認已安裝成功。
You can also use the .NET Framework to complete this tutorial however the setup steps will be different.
你也能夠使用 NET Framework 來完成本教程,然而其安裝步驟會有所不一樣。
RabbitMQ .NET client 5.0 and later versions are distributed via nuget.
RabbitMQ .NET client 5.0 以及最新的版本是經由 Nuget 來發布的。
This tutorial assumes you are using powershell on Windows. On MacOS and Linux nearly any shell will work.
本教程假定你在 Windows 操做系統中會使用 PowerShell,能夠放心的是,在 MacOS 和 Linux 中幾乎全部的 Shell 環境都能正常運行。
安裝
First lets verify that you have .NET Core toolchain in PATH:
首先讓咱們驗證一下本地環境變量 PATH 中的 .NET Core 工具鏈:
dotnet --help
should produce a help message.
這時應當產生一個幫助消息。
Now let's generate two projects, one for the publisher and one for the consumer:
如今讓咱們來建立兩個項目,一個是發佈者,一個是消費者。
dotnet new console --name Send mv Send/Program.cs Send/Send.cs dotnet new console --name Receive mv Receive/Program.cs Receive/Receive.cs
This will create two new directories named Send and Receive.
這一步將會建立兩個文件夾,一個叫 Send,一個叫 Receive。
Then we add the client dependency.
緊接着咱們來添加客戶端依賴。
cd Send dotnet add package RabbitMQ.Client dotnet restore cd ../Receive dotnet add package RabbitMQ.Client dotnet restore
Now we have the .NET project set up we can write some code.
好了,如今咱們完成了 .NET 項目的安裝,這樣就能夠寫一些代碼了。
發送
We'll call our message publisher (sender) Send.cs and our message consumer (receiver) Receive.cs. The publisher will connect to RabbitMQ, send a single message, then exit.
隨後咱們會調用消息發佈者(發送)Send.cs,以及消息消費者(接收)Receive.cs。發佈者會鏈接 RabbitMQ,併發送一條消息,而後退出。
In Send.cs, we need to use some namespaces:
在 Send.cs 中,咱們須要引入一些命名空間:
using System; using RabbitMQ.Client; using System.Text;
Set up the class:
創建類文件:
class Send { public static void Main() { ... } }
then we can create a connection to the server:
而後咱們就能夠建立一個通往服務器的鏈接。
class Send { public static void Main() { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { ... } } } }
The connection abstracts the socket connection, and takes care of protocol version negotiation and authentication and so on for us. Here we connect to a broker on the local machine - hence the localhost. If we wanted to connect to a broker on a different machine we'd simply specify its name or IP address here.
該鏈接是抽象自套接字鏈接,爲咱們處理協議關於版本在協商與認證等方面的事宜。在這裏,咱們會鏈接到本地機器的一個代理,也就是 localhost。若是咱們想鏈接到一臺不一樣機器上的代理,只需簡單地指定主機名或者 IP 地址。
Next we create a channel, which is where most of the API for getting things done resides.
接下來咱們將建立一個信道,它在衆多的 API 中負責着事項的正確處理。
To send, we must declare a queue for us to send to; then we can publish a message to the queue:
爲了能順利的發送,咱們須要先定義一個隊列,而後咱們就能夠發佈消息了。
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(); } }
Declaring a queue is idempotent - it will only be created if it doesn't exist already. The message content is a byte array, so you can encode whatever you like there.
聲明隊列的行爲是冪等性的 - 即只有當一個隊列不存在時才能被建立。
When the code above finishes running, the channel and the connection will be disposed.
當上述代碼完成時,信道和鏈接將會被釋放。
Here's the whole Send.cs class.
發送運行失敗
If this is your first time using RabbitMQ and you don't see the "Sent" message then you may be left scratching your head wondering what could be wrong. Maybe the broker was started without enough free disk space (by default it needs at least 50 MB free) and is therefore refusing to accept messages. Check the broker logfile to confirm and reduce the limit if necessary. The configuration file documentation will show you how to set disk_free_limit.
若是這是你第一次使用 RabbitMQ,而且你沒有收到「Sent」這一消息,這時你可能會抓耳撓腮,想知道是什麼致使了錯誤。在這種狀況下,有很大多是由於代理(broker)在啓動時沒有足夠的可用磁盤空間(默認至少須要 50M ),所以拒絕接收消息。檢查代理(broker)日誌文件(logfile),並進行確認以減小限制,經過查看配置文件文檔,能夠知曉如何設置 disk_free_limit。
接收
That's it for our publisher. Our consumer is pushed messages from RabbitMQ, so unlike the publisher which publishes a single message, we'll keep it running to listen for messages and print them out.
以上是咱們的發佈者。咱們的消費者已開始從 RabbitMQ 上被推送了消息,與發送一條消息的發佈者有所不一樣的是,咱們會讓消費者持續地監聽消息並將其打印出來。
The code (in Receive.cs) has almost the same using statements as Send:
在 Receive.cs 類文件中,using 區域的聲明代碼與 Send.cs 類文件近乎相同:
using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text;
Setting up is the same as the publisher; we open a connection and a channel, and declare the queue from which we're going to consume. Note this matches up with the queue that send publishes to.
與發佈者的設置同樣,咱們打開一個鏈接和信道,而且聲明好隊列以做好消費的準備。須要注意的是,該隊列與發佈者所發送消息的隊列是相匹配的(即基於同一個隊列)。
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); ... } } } }
Note that we declare the queue here, as well. Because we might start the consumer before the publisher, we want to make sure the queue exists before we try to consume messages from it.
能夠看到咱們在消費者這裏又聲明瞭一次隊列(QueueDeclare),在實踐中,咱們極可能是先啓動消費者,後啓動發佈者。因此重複的聲明代碼,是當咱們嘗試從隊列中消費消息時,確保隊列老是已存在的。
We're about to tell the server to deliver us the messages from the queue. Since it will push us messages asynchronously, we provide a callback. That is what EventingBasicConsumer.Received event handler does.
咱們即將告知服務器從隊列中向咱們遞送消息,由於該動做是基於異步的,因此咱們須要提供回調,這即是 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(); } } }
Here's the whole Receive.cs class.
融合一塊兒
Open two terminals.
打開兩個終端。
Run the consumer:
運行消費者:
cd Receive dotnet run
Then run the producer:
緊接着運行生產者:
cd Send dotnet run
The consumer will print the message it gets from the publisher via RabbitMQ. The consumer will keep running, waiting for messages (Use Ctrl-C to stop it), so try running the publisher from another terminal.
消費者會經由 RabbitMQ 打印出那些來自發布者的消息。消費者會持續運行,以等待消息(使用 Ctrl-C 來終止運行),如此,咱們能夠嘗試從其餘終端來運行發佈者(重複運行多個生產者實例程序)。