# 以 MQTT RabbitMQ 服務安裝在 docker 並搭配 .NET 6 進行實作發佈與訂閱
[toc]

## 安裝 RabbitMQ on Docker for Windows

[docker hub rabbitmq](https://hub.docker.com/_/rabbitmq)
1. 輸入 pull 指令下載 image
`$ docker pull rabbitmq`
2. 建立 Container
`$ docker run -d --hostname my-rabbit --name rock-rabbit rabbitmq:3`
`$ docker run -d --name rock-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:management`
> 預設 Port:5672
> --name rock-rabbit 表示將 Container 名稱設定為 rock-rabbit
> rabbitmq:3 表示使用 rabbitmq tag 等於 3 的版本來建 Container
3. 設置預設用戶和密碼(請參考 docker 官方文件)
> 預設使用者名稱和密碼都是 `guest`
4. 進入管理網站
> http://127.0.0.1:15672/

登入成功

> 當然你也可以綁定本機某一個 Port 號,來對應 15672 Container(請參考 docker 官網)
## 建立 Publisher 發佈者和 Consumer 訂閱者的帳號與密碼



## 建立訊息通道


# 撰寫一個 RabbitMQ 的 .NET 範例
## 安裝套件 RabbitMQ.Client

## 程式範例
### Publisher 發佈者程式
```csharp=
internal class Program
{
static readonly string queueName = "stocktick";
static void Main(string[] args)
//傳送端代碼
//創建連線工廠(ConnectionFactory)物件:這個物件用於設定與 RabbitMQ 伺服器的連線參數,包括使用者名稱、密碼、虛擬主機、主機名稱和埠號等。
ConnectionFactory factory = new ConnectionFactory();
factory.UserName = "send";
factory.Password = "send";
factory.VirtualHost = "/";
factory.HostName = "localhost";
factory.Port = 5672; // AmqpTcpEndpoint.UseDefaultPort;
//創建連線(IConnection)物件:使用連線工廠創建一個連線至 RabbitMQ 伺服器。
IConnection connection = factory.CreateConnection();
int i = 0;
//創建通道(IModel)物件:使用連線創建一個通道,通道用於執行 RabbitMQ 的各種操作,如隊列宣告、訊息發佈等。
using (var channel = connection.CreateModel())
{
//宣告隊列:使用通道的 QueueDeclare 方法宣告一個隊列,指定隊列的名稱(queue)、是否持久化(durable)、是否獨佔(exclusive)、是否自動刪除(autoDelete)、和額外的參數(arguments)。
channel.QueueDeclare(queue: queueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
while (i < 5)
{
string message = "Hello World! " + i;
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "", routingKey: queueName, basicProperties: null, body: body);
Console.WriteLine(" [x] Sent {0}", message);
Thread.Sleep(1000);
i++;
}
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
```
### Consumer 訂閱者程式
```csharp=
internal class Program
{
static readonly string queueName = "stocktick";
static void Main(string[] args)
{
Task threadTask = Task.Run(() => t1());
//threadTask.Wait(); // 等待任務完成
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
static bool isQuitThread = false;
private static void t1()
{
//建立接收者連線資訊
ConnectionFactory factory = new ConnectionFactory();
factory.UserName = "receive";
factory.Password = "receive";
factory.VirtualHost = "/";
factory.HostName = "localhost";
factory.Port = 5672;//AmqpTcpEndpoint.UseDefaultPort;
IConnection connection = factory.CreateConnection();
//產生通道
using var channel = connection.CreateModel();
//宣告隊列:使用通道的 QueueDeclare 方法宣告一個隊列,指定隊列的名稱(queue)、是否持久化(durable)、是否獨佔(exclusive)、是否自動刪除(autoDelete)、和額外的參數(arguments)。
channel.QueueDeclare(queue: queueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
Console.WriteLine(" [*] Waiting for messages.");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
//讓程式不要直接結束
while (isQuitThread) ;
Debug.WriteLine("thread is quit!!");
}
}
```
# 支援的程式語言
https://www.rabbitmq.com/devtools.html
# 參考資料
[.NET/C# Client API Guide](https://www.rabbitmq.com/dotnet-api-guide.html)
[MQTT教學(一):認識MQTT](https://swf.com.tw/?p=1002)
[【RabbitMQ】五分鐘輕鬆了解 RabbitMQ 運作](https://zamhuang.medium.com/rabbitmq-%E4%BA%94%E5%88%86%E9%90%98%E8%BC%95%E9%AC%86%E4%BA%86%E8%A7%A3-rabbitmq-%E9%81%8B%E4%BD%9C-fcaecbaa69d4)
[用 Docker 玩 RabbitMQ](https://hackmd.io/@SuFrank/rJ5Tgyb6q)
###### tags: `MQTT` `RabbitMQ`