關於訪問MSMQ遠端私有隊列的一點經驗


這里應該將私有隊列稱做“專用隊列”好像更貼切一些了,O(∩_∩)O

可以訪問遠程主機的MSMQ的私有隊列的,這個是毋庸置疑的,但需要說明的是不能通過代碼創建私有隊列,關於這一點,我也不知道為什么?

下面說說我的經驗
1、首先要保證遠端的主機和本地機器同時加入到了同一個域中
2、要通過管理工具在遠端主機中創建私有的隊列,例如 192.168.117.47\Private$\MyPath,可以在創建時指定是否啟用事務
3、在本地無法得到遠端是否存在指定的私有隊列,也無法得到指定的私有隊列是否已經啟用了事務,因此在編碼時,最好能明確的知道遠端已經創建了這個私有隊列,並且這個私有隊列是否已經啟用了事務
4、下面給出遠端私有隊列的格式
     如果是 IP 地址的形式,請使用 "FormatName:DIRECT=TCP:" + 遠端IP + @"\private$" + @"\" + 私有隊列的路徑名稱
    如果是機器名的方式,請使用 "FormatName:DIRECT=OS:" +遠端的主機名 +    @"\private$" + @"\" + 私有隊列的路徑名稱 
5、要保證本機和遠端的主機使用同樣的域賬戶登錄,最好這個賬戶也是本機及遠端機的系統管理員組成員
 
發送消息
public bool SendMessage(string path, object source, bool transactional = false){
// 注意路徑的格式見本日志(一)的部分 
if (!string.IsNullOrWhiteSpace(path) && source != null)
            { 
                try
                {
                    using (MessageQueue mqSender =  new  MessageQueue  (path))
                    {
                        mqSender.MessageReadPropertyFilter.Body = true;
                        mqSender.MessageReadPropertyFilter.AppSpecific = true;
                        mqSender.MessageReadPropertyFilter.Priority = true;
                        mqSender.MessageReadPropertyFilter.Recoverable = true; // 防止重啟主機時丟失消息
                        mqSender.Formatter = new XmlMessageFormatter(new Type[] { source.GetType() });
                        if ( transactional   == true)
                        {
                            using (MessageQueueTransaction tran = new MessageQueueTransaction())
                            {
                                tran.Begin();
                                mqSender.Send(source, tran);
                                tran.Commit();
                            }
                        }
                        else
                            mqSender.Send(source);
                        mqSender.Close();
                    }
                    return true;
                }
                catch (MessageQueueException ex)
                {
                    Console.Write(ex);
                }
                catch (Exception ex)
                {
                    Console.Write(ex);
                }
            }
            return false;
        }
 
接收消息
 public static T GetMessage<T>(string path, bool isDeleteMessage = true, bool t ransactional = false)
        {
            T result = default(T);
            try
            {
                using (MessageQueue mqReceiver = new MessageQueue(path))
                {
                    mqReceiver.MessageReadPropertyFilter.Body = true;
                    mqReceiver.MessageReadPropertyFilter.AppSpecific = true;
                    mqReceiver.MessageReadPropertyFilter.Priority = true;
                    mqReceiver.MessageReadPropertyFilter.Recoverable = true; // 防止重啟主機時丟失消息
                    mqReceiver.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
                    Message message = null;
                    if ( transactional  == true)
                    {
                        if (isDeleteMessage == true)
                        {
                            using (MessageQueueTransaction tran = new MessageQueueTransaction())
                            {
                                tran.Begin();
                                Console.WriteLine("等待接收......");
                                message = mqReceiver.Receive(tran);
                                Console.WriteLine("接到了");
                                tran.Commit();
                            }
                        }
                        else
                            message = mqReceiver.Peek();
                    }
                    else
                    {
                        if (isDeleteMessage)
                        {
                            Console.WriteLine("等待接收......");
                            message = mqReceiver.Receive();
                            Console.WriteLine("接到了");
                        }
                        else
                            message = mqReceiver.Peek();
                    }
                    if (message != null)
                        result = (T)message.Body;
                    mqReceiver.Close();
                }
            }
            catch (MessageQueueException ex)
            {
                Console.Write(ex);
            }
            catch (Exception ex)
            {
                Console.Write(ex);
            }
            return result;
        }
 
申:
以下代碼在調試遠端的主機時會出現異常
bool b = MessageQueue.Exists(path); // 按說應該不會,但是我的機器調試時總出錯,不知道為什么?
MessageQuene m = MessageQuene.Create(path);// 不知道,反正沒有通過
bool b = m.Transactional; // 好像在遠端時不支持這個屬性了
以上信息在本地時沒有任何問題,O(∩_∩)O~
 
一點補充:
以下只在本地有效,不知道遠端是否有效,沒試過
如何得到本地的私有隊列中的消息的數量(主要代碼如下:)
     using System.Diagnostics;     
    return (long)(new PerformanceCounter("MSMQ Queue", "Messages in Queue", path).NextValue());
如果在執行以上代碼時出現注冊表缺少什么等等的 InvalidOperationException 時,請以管理員的方式在 DOS 中執行
命令 "lodctr /R",也可以通過命令 "perfmon" 查看性能計數器的情況
另外說明在 path 中本地機器名要給全例如 @"MyPC\Private$\MyPath",不能用省略符號 @".\Private$\MyPath"替代
在進行MSMQ的編程時,請添加引用 System.Message.dll 並添加對應的命名空間的引用
 
其實除了 MSMQ ,我們還是有很多其他的選擇的,例如 ActiveMQ 等等,有興趣大家可以看看了......
 
關於在集群中使用隊列
1、要在集群中使用隊列,請在集群中的每個主機的私有隊列中創建自己的隊列(最好創建事務性隊列),例如我的集群中包含兩台主機 192.168.117.47、192.168.117.48,共同的漂移地址是192.168.117.50,那我就在每台主機的 MSMQ 的私有隊列中分別創建 \private$\MyPath (創建時指定帶有事務)
2、在創建隊列之后,請在隊列的屬性中指定用戶及該用戶對隊列的訪問權限,否則訪問隊列的客戶端程序將不能正確的發送和接收隊列。
3、發送消息時,要使用漂移地址 192.168.117.50 發送, 同時指定發送消息時要 啟用事務
4、接收消息時,請使用單機的 IP 192.168.117.47 或 192.168.117.48 接收隊列,同時,請 不要指定接收消息的隊列啟用事務,嘿嘿,這里是不是和不在集群時的情況有些不同,同時也和發送消息有些不一樣呢?!
5、之前給出的代碼是采用的格式化是 XmlMessageFormatter,這就要求在接收消息時必須要知道消息中對象的類型,如果我們在發送和接收消息時指定 MessageQueue.Formatter = new BinaryMessageFormatter(),則可以在發送和接收消息時不用知道消息中包含的對象的類型了
 
之前的接收都是同步接收消息,有沒有辦法來異步獲取消息呢?當然可以,代碼如下:
主調方代碼:
MessageQueue mq = GetMessageQueue(path); // GetMessageQueue 函數如何實現就不寫了吧?!
mq.ReceiveCompleted += new ReceiveCompletedEventHandler(mq_ReceiveCompleted);
mq.BeginReceive();
 
回調函數
private void  mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
            MessageQueue mq = sender as MessageQueue;
            if (mq != null && e != null)
            {
                Message message = mq.EndReceive(e.AsyncResult);
                if (message != null)
                    Console.WriteLine(message.Body);
                mq.BeginReceive();
            }
}
這是接收消息之后就刪除的代碼,當然也可以做接收消息但不刪除的,這里就不再熬訴了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM