使用 MSMQ 進行 C# 客戶端與服務端通信
概述
Microsoft Message Queuing (MSMQ) 是一種消息隊列技術,可用於不同應用程式或機器之間的異步通信。本篇文章將介紹如何使用 MSMQ 實現簡單的 C# 客戶端與服務端通信,並提供異步監聽、錯誤處理及重試機制的最佳實踐。
需求
- 客戶端發送 "OK" 指令至 MSMQ 佇列。
- 服務端監聽 MSMQ,當收到 "OK" 時,回應 "Hello"。
- 支援異步監聽,提高效能。
- 加入錯誤處理與自動重試機制。
- 記錄錯誤日誌,確保系統可觀測性。
MSMQ 基礎
在開始開發前,請確保 Windows 已安裝 MSMQ。
控制台開啟 MSMQ
PowerShell 開啟 MSMQ:
Enable-WindowsOptionalFeature -Online -FeatureName MSMQ-Server
開啟防火牆端口(TCP 1801):
netsh advfirewall firewall add rule name="Allow MSMQ" dir=in action=allow protocol=TCP localport=1801
客戶端程式碼(發送消息至指定 IP)
using System;
using System.Messaging;
class MsmqClient
{
static void Main()
{
string targetIP = "192.168.1.100"; // 目標 MSMQ 伺服器的 IP
string queueName = "TestQueue"; // 目標 MSMQ 佇列名稱
string queuePath = $"FormatName:DIRECT=OS:{targetIP}\\private$\\{queueName}";
try
{
using (MessageQueue mq = new MessageQueue(queuePath))
{
mq.Label = "RemoteTestQueue";
mq.Send("OK", "Client Message");
Console.WriteLine($"客戶端:發送 OK 指令到 {targetIP}");
}
}
catch (Exception ex)
{
Console.WriteLine($"發送失敗: {ex.Message}");
}
}
}
服務端程式碼(異步監聽 MSMQ,帶錯誤處理與重試機制)
using System;
using System.IO;
using System.Messaging;
using System.Threading;
class MsmqServer
{
private static string queuePath = @".\private$\TestQueue";
private static MessageQueue mq;
private static int maxRetryCount = 3; // 最大重試次數
private static string logFilePath = "msmq_error.log"; // 錯誤日誌文件
static void Main()
{
if (!MessageQueue.Exists(queuePath))
{
Console.WriteLine("隊列不存在,正在創建...");
MessageQueue.Create(queuePath);
}
mq = new MessageQueue(queuePath);
mq.Formatter = new XmlMessageFormatter(new string[] { "System.String" });
Console.WriteLine("服務端:等待來自遠端的消息...");
mq.BeginReceive(new TimeSpan(0, 0, 10), null, new AsyncCallback(MessageReceived));
while (true) { Thread.Sleep(5000); }
}
private static void MessageReceived(IAsyncResult ar)
{
try
{
Message msg = mq.EndReceive(ar);
string receivedText = msg.Body.ToString();
Console.WriteLine($"收到消息: {receivedText}");
if (receivedText == "OK")
{
Console.WriteLine("服務端回應: Hello");
}
mq.BeginReceive(new TimeSpan(0, 0, 10), null, new AsyncCallback(MessageReceived));
}
catch (MessageQueueException ex)
{
LogError($"MSMQ 錯誤: {ex.Message}");
RetryReceive();
}
}
private static void RetryReceive()
{
for (int i = 1; i <= maxRetryCount; i++)
{
try
{
Console.WriteLine($"重試中 ({i}/{maxRetryCount})...");
Message msg = mq.Receive(new TimeSpan(0, 0, 10));
msg.Formatter = new XmlMessageFormatter(new string[] { "System.String" });
string receivedText = msg.Body.ToString();
Console.WriteLine($"收到消息 (重試成功): {receivedText}");
if (receivedText == "OK")
{
Console.WriteLine("服務端回應: Hello");
}
break;
}
catch (Exception retryEx)
{
LogError($"重試失敗 ({i}): {retryEx.Message}");
if (i == maxRetryCount)
{
Console.WriteLine("已達最大重試次數,消息將丟失。");
}
}
}
}
private static void LogError(string message)
{
Console.WriteLine($"錯誤記錄: {message}");
File.AppendAllText(logFilePath, $"{DateTime.Now}: {message}{Environment.NewLine}");
}
}
電腦已建立的住列服務佇列服務
測試與驗證
- 啟動 MSMQ 伺服器,確認
TestQueue
存在。 - 在遠端機器上運行服務端 (
MsmqServer.exe
)。 - 在本機或其他客戶端運行 MSMQ 發送程式 (
MsmqClient.exe
)。 - 服務端應該成功接收 "OK" 並輸出 "Hello"。
- 手動關閉 MSMQ 或停止服務端,並嘗試發送消息,應能記錄錯誤日誌 (
msmq_error.log
)。
結論
本文介紹了如何使用 C# 和 MSMQ 進行可靠的消息通信,並加入了異步監聽、錯誤處理與重試機制,以提高系統穩定性。如果有更進階的需求,如消息持久化到資料庫或整合雲端消息系統,可以進一步擴展 MSMQ 應用。