1. 程式人生 > >RabbitMQ ——“Hello World”

RabbitMQ ——“Hello World”

二進制 program ets 程序 sum blob 可用 run 客戶

介紹

RabbitMQ是一個消息實體服務(broker):它接收及轉發消息。你可以把它想象成一個郵局:當你把你想要寄送的郵件放進郵箱裏時,你能夠確信郵局的派送員最終會把你的這封郵局送到這信的收件者手中。以這個類比來說,RabbitMQ就是郵箱,郵局和郵局的派送員。 RabbitMQ和這個郵局最大的區別,是RabbitMQ不是與紙張打交道,而是接受、儲存和轉發二進制數據塊——消息。 RabbitMQ 和一般通信中使用的一些術語: 生產就只是意味著發送。一個發送消息的程序就是生產者: 技術分享圖片 隊列是存在於RabbitMQ裏的一個郵箱的名字。盡管消息流過RabbitMQ和你的應用程序,但他們只被存儲於隊列裏。隊列只受限於主機的內存和磁盤。它本質上是一個很大的消息緩沖區。一些生成者能夠發送消息到一個隊列裏,同時一些消費者可以嘗試從那個隊列裏接受數據。下圖就是我們描述的一個隊列: 技術分享圖片
消費有著類似於接收的意思。一個消費者就是一個主要等待接收消息的程序: 技術分享圖片 註意:生產者、消費者,以及消息實體服務不一定是寄居於同一臺主機;事實上在大部分應用中,它們不是在同一臺主機裏。

“Hello World”

註意:這個教程中的例子,假設你已經安裝了RabbitMQ,而且運行在本地的標準端口(5672)。萬一你使用了不同的主機,端口或證書,那你需要調整連接設置。

(使用 .NET/C# Client)

在這部分教程中,我們將用C#來寫兩個程序:一個用來發送一條消息的生成者,和一個接受消息並把消息打印出來的消費者。我們將忽略.net client API 中的一些細節,作為一個開始我們只專註於這些很簡單的東西。這是一個“Hello World”消息。 在下面的示意圖中,“P”就是我們的生成者,"C"就是我們的消費者。中間的盒子就是一個隊列,隊列就是RabbitMQ 為消費者保留的一個消息緩沖區。 技術分享圖片

.Net 客戶端類庫 RabbitMQ 可以使用多種協議。這個教程中使用AMQP 0-9-1,這是一個消息通信中開放而多用途的協議。對於RabbitMQ,可以使用多種不同的語言寫成的客戶端。我們這裏將使用RabbitMQ提供的.net 客戶端。 這個客戶端支持.Net Core,跟支持.net framework4.5.1以上一樣。在這個教程中將使用RabbitMQ .net client 5.0 和.net core,所以你必須確保你已經安裝了,而且在你的PATH裏。 你同樣可以使用.net framework來完成這個教程中的示例,但是建立項目的步驟將會不一樣。 RabbitMQ .NET client 5.0 及最新版通過nuget發布。
這個教程假設你的windows是使用了powershell。在MacOS和Linux幾乎任何shell都可以。

建立項目

首先我們先來確認.net core toolchain 在PATH: 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中,我們需要引用一些命名空間:
1 2 3 using System; using RabbitMQ.Client; using System.Text;

建立這個類:

1 2 3 4 5 6 7 class Send { public static void Main() { ... } }

然後我們創建一個到服務器的連接:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 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處理任務都是在這裏完成的。 對於發送,我們必須聲明一個隊列用來發送消息;然後我們發布一條消息到這個隊列中:
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 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,而且你沒有看到你發送的消息,你可能會抓耳撓腮地在想,到底是哪裏出錯了。這可能是消息服務實體啟動時沒有足夠的可用磁盤空間(默認是至少需要50M的可用空間),而導致它拒絕接受消息。如果需要的話,檢查消息服務實體日誌來確認和減少這種限制。這個 configuration file documentation(配置文檔)將告訴你如何設置disk_free_limit

接受

上面是我們的發布者。我們的消費者是從RabbitMQ中拉取消息,接受者不同於發布者只發布一條消息,我們將保持接收者一直監聽消息及將其打印出來。 技術分享圖片 這個代碼(Receive.cs)幾乎使用了跟Send一樣的命名空間:
1 2 3 4 using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text;

創建一個接收方和創建發布者是一樣的;我們先打開連接和一個通道,然後聲明一個我們制定要去哪裏拉取消息的隊列。註意這個要匹配Send中發布消息的隊列。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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事件來處理的。
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 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來停止),所以可以嘗試在另一個終端運行發布者。 PS:這是第一次翻譯,翻譯得不好,原因之一是自己對於RabbitMQ不熟,由於目前工作中右接觸到RabbitMQ,所以自己就正在補這方面的知識,自己也順便嘗試一下翻譯,自己感覺翻譯真的是個有點揪心的事,很多英文句子看起來很簡單,但是翻譯出來的中文,卻總覺得怪怪的。 如果你是使用.net framwork,一樣是通過nuget獲取RabbitMQ.Client的引用,其它的一樣,這個在博客園有很多的例子,可以自己去找一下。

RabbitMQ ——“Hello World”