使用 MSMQ 進行 C# 客戶端與服務端通信

概述

Microsoft Message Queuing (MSMQ) 是一種消息隊列技術,可用於不同應用程式或機器之間的異步通信。本篇文章將介紹如何使用 MSMQ 實現簡單的 C# 客戶端與服務端通信,並提供異步監聽、錯誤處理及重試機制的最佳實踐。

需求

  • 客戶端發送 "OK" 指令至 MSMQ 佇列。
  • 服務端監聽 MSMQ,當收到 "OK" 時,回應 "Hello"。
  • 支援異步監聽,提高效能。
  • 加入錯誤處理與自動重試機制。
  • 記錄錯誤日誌,確保系統可觀測性。

MSMQ 基礎

在開始開發前,請確保 Windows 已安裝 MSMQ。

控制台開啟 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}");
    }
}

電腦已建立的住列服務佇列服務

image-20250216200729380.png

測試與驗證

  1. 啟動 MSMQ 伺服器,確認 TestQueue 存在。
  2. 在遠端機器上運行服務端 (MsmqServer.exe)
  3. 在本機或其他客戶端運行 MSMQ 發送程式 (MsmqClient.exe)
  4. 服務端應該成功接收 "OK" 並輸出 "Hello"。
  5. 手動關閉 MSMQ 或停止服務端,並嘗試發送消息,應能記錄錯誤日誌 (msmq_error.log)。

結論

本文介紹了如何使用 C# 和 MSMQ 進行可靠的消息通信,並加入了異步監聽、錯誤處理與重試機制,以提高系統穩定性。如果有更進階的需求,如消息持久化到資料庫或整合雲端消息系統,可以進一步擴展 MSMQ 應用。

Last modification:February 16, 2025
If you think my article is useful to you, please feel free to appreciate