##介紹
RabbitMQ是一個消息代理。它的核心原理非常簡單:接收和發送消息。你可以把它想像成一個郵局:你把信件放入郵箱,郵遞員就會把信件投遞到你的收件人處。在這個比喻中,RabbitMQ是一個郵箱、郵局、郵遞員。RabbitMQ和郵局的主要區別是,它處理的不是紙,而是接收、存儲和發送二進制的數據——消息。
一般提到RabbitMQ和消息,都用到一些專有名詞。
- **生產(Producing)**意思就是發送。發送消息的程序就是一個生產者(producer)。我們一般用”P”來表示:

- **隊列(queue)**就是郵箱的名稱。消息通過你的應用程序和RabbitMQ進行傳輸,它們能夠只存儲在一個隊列(queue)中。隊列(queue)沒有任何限制,你要存儲多少消息都可以——基本上是一個無限的緩沖。多個生產者(producers)能夠把消息發送給同一個隊列,同樣,多個消費者(consumers)也能夠從一個隊列(queue)中獲取數據。隊列可以用下圖標識:

- 消費(Consuming)和獲取消息是一樣的意思。一個消費者(consumer)就是一個等待獲取消息的程序。我們把它畫作”C”:

> **注意:**一般生產者,消費者和代理不必部署在同一臺機子上。
##Hello World 示例
###簡介
我們的“Hello world”不會很復雜——僅僅發送一個消息,然后獲取它并輸出到屏幕。這樣以來我們需要兩個程序,一個用作發送消息,另一個接受消息并打印消息內容。
大體的設計如下所示:

###Sending 發送端

我們會創建一個**Send.cs**,來實現,連接**RabbitMQ**,發送一條簡單的信息,然后退出。
首先在**Send.cs**中,我們需要添加必要的命名空間
```
using System;
using RabbitMQ.Client;
using System.Text;
```
創建類
```
class Send
{
public static void Main()
{
...
}
}
```
接下來,創建與RabbitMQ Server 的連接
```
class Send
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
...
}
}
}
}
```
這里創建了一個Socket連接,負責協議版本協商和身份驗證等等,這里由于連接的是本地機子,所以取值`localhost`。
接下來,創建一個channel(通道),大多數任務都是在這里完成的。
要發送消息,我們必須首先定義一個**queue(隊列)**,然后我們才成把消息發送給**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();
}
}
```
queue 的定義具有冪等性(一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相等),因此定義的queue已經存在,不會重復定義,且不能修改。
當上面的代碼執行完,channel 和connection會disposed(處理掉,釋放掉)。
###Receiving 接收端
接收端會從 RabbitMQ server 拉取消息,因此接收端 要監聽消息,然后打印輸出

與Send.cs代碼一樣,引用必要的命名空間
```
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
```
同Sender 接收端一樣,我們要打來 一個connection和channel,定義一個queue用來從中獲取消息。
```
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:也許你已經發現,我們在接收端也定義了hello隊列。這是為了確保,如果接收端先啟動的時候,隊列已經存在。
接下來,我們就要告訴服務器來交付消息。由于推送消息是一個異步操作,因此我們使用回調函數,這里我們使用`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",
noAck: true,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
```
##演示
首先我們要將 RabbitMQ.NET Client 程序集和上面的代碼文件放到一起
接下來,我們可以打開` Visual Studio 命令提示工具`,`cd`到上面代碼說在文件夾,運行下面的命令來編譯代碼。
```
$ csc /r:"RabbitMQ.Client.dll" Send.cs
$ csc /r:"RabbitMQ.Client.dll" Receive.cs
```
我們會在文件所在目錄下,看到生成的Send.exe 和Receive.exe
我們運行連個程序。
先運行
`
$ Send.exe
`
會看到提示 發送的信息
接下來運行
`
$ Receive.exe
`
我們會看到 顯示我們之前發送的消息。
接收端會獲取發送端通過RabbitMQ 發送的消息。接收端會一直執行,接收發送端發送的消息。
如果這個時候,我們再另外打開Send.exe,我們會看到接收端顯示新的消息。
如果我們想查看隊列的信息,我們可以使用下面的命令
```
rabbitmqctl list_queues.
```