標籤:lin 百度 machine 設定 說明 解決辦法 edr 格式 param
轉:https://www.cnblogs.com/80X86/p/5557801.html
功能需求,用到了隊列,用的時候出了很多問題,現在總結一下,希望能對有需要的人提供協助。
我的需求很簡單,就是多個用戶端串連到我的一個小型的資料轉寄伺服器上,開始使用的是Socket通訊實現這個功能,一旦資料服務器接收到來自不同用戶端發來的訊息,就對這些訊息進行處理(我這裡是將資料接收到後再轉寄到另一個伺服器上),但考慮到用戶端是每隔一個很短的時間周期向伺服器發送資訊,並且串連客服端數量比較多的時候,擔心會產生並發訪問的問題,也希望避免 資料轉寄伺服器 頻繁地從多個不同線程擷取資訊而出現其他未知問題,所以在處理用戶端向資料轉寄伺服器發送資訊的時候採取隊列的方式。
一般情況下,使用MSMQ,要先安裝Message Service,這個直接百度就行;
在VS裡添加 Messaging引用,就可以使用MessageQueue這個類了;接下來就要思考清楚你的資料(訊息)的流向問題,之前因為自己對隊列的錯誤認識,對到底在哪建立隊列,隊列的訊息又由誰去發送和接收沒有弄清除,還有參考的一些寫得不是太清晰地博文,繞了好大一圈,所以今天在這裡以我自己的項目需求為例子,說明 1、如何建立隊列 2、如何向隊列發送訊息 3、 如何擷取隊列中的訊息
首先、建立隊列:根據我的需求,我要通過Socket通訊將資訊發送至資料轉寄伺服器,因此為了避免並發訪問問題的產生,訊息佇列應當建立在資料轉寄伺服器上;
MessageQueue myqueue = null; string queuepath = @".\private$\queuedemo"; if (!MessageQueue.Exists(queuepath)) { myqueue = MessageQueue.Create(queuepath); } myqueue = new MessageQueue(queuepath);
View Code
這樣就在資料轉寄伺服器端建立了一個名為queuedemo的訊息佇列;從用戶端要發送的訊息就儲存在這個隊列裡,你可以通過電腦管理->服務和應用下的訊息佇列中看到你建立的queuedemo隊列,private$關鍵字是說明隊列為專用隊列,如果沒有這個關鍵字還要佈建網域伺服器,還是挺麻煩,這個還是藉助百度吧,前面的“.”代表建立的隊列目錄是本機,這個隊列一旦建立成功,就是系統的事了,接下來要做的就是你怎麼去把訊息寫進這個隊列,或者讀取隊列的值 這裡要特別注意,不要將queuepath路徑字串寫成
string queuepath = @"FormatName:Direct=TCP:192.168.1.153\private$\queuedemo";
這樣寫的話是用於遠端電腦對這個隊列進行訪問的,因為MessageQueue的Create()和Exisit()方法是沒辦法去識別上述FormatName格式的,還有要確保Create()函數要被執行了之後再用MessageQueue執行個體去引用;這樣伺服器端隊列的建立就完成了;
在用戶端中,向隊列發送資訊;
string s = "用戶端往隊列裡發送的資訊"); System.Messaging.Message msg = new System.Messaging.Message(); msg.Body = s; msg.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); MessageQueue mq = new MessageQueue(@"FormatName:Direct=TCP:192.168.1.153\private$\queuedemo"); mq.Send(msg);
View Code
在用戶端中,用一個MessageQueue執行個體指向伺服器本機上建立的隊列路徑,這時,MessageQueue執行個體的建構函式裡的路徑就一定要用FormatName格式,指明是TCP通訊還是HTTP還是Machine如我上面代碼所示,然後調用Send()方法,將訊息寫進隊列,這個要求發送的對象要以序列化的方式寫進去,所以要設定formatter,這裡用的是XmlMessageFormatter 還有BinaryMessageFormatter等等 注意儲存你訊息的 訊息體Body是Object類型的 因此可以將你寫的任何一個類的對象發送至訊息佇列
在伺服器中接收訊息佇列
MessageQueue mq = new MessageQueue(@".\private$\queuedemo"); mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); Thread th = new Thread(() => { while (true) { System.Messaging.Message msg = mq.Receive(); if (msg != null) { MessageBox.Show(msg.Body.ToString()); } } }); th.IsBackground = true; th.Start();
View Code
在本機上可以新建立一個隊列執行個體指向原生隊列,然後按照之前約定的序列化格式還原序列化訊息體所以將新的隊列執行個體的foarmatter屬性賦值為發送時的formatter屬性如代碼所示,這個時候就直接用Receive()得到訊息體,然後對訊息體裡的資訊做處理,我這裡是開啟一個線程顯示隊列的訊息,只要有新的訊息寫入,我就在訊息框中輸出
這個時候可能用戶端無法向遠程伺服器成功發送訊息,原因基本許可權問題 伺服器的訊息佇列的許可權沒有對未驗證的用戶端開放 你要在伺服器隊列裡分配對應許可權 如果你想讀取隊列的內容 還需要加系統變數
問題解決辦法
1. 伺服器端
伺服器上訊息佇列使用權限設定:給ANONYMOUS LOGON賦予所有許可權;
修改伺服器的註冊表,允許非驗證用戶端訪問
- 註冊表新增HKLM\Software\Microsoft\MSMQ\Parameters\security\AllowNonauthenticatedRpc項,設定其DWORD值為1
- 註冊表新增HKLM\Software\Microsoft\MSMQ\Parameters\security\NewRemoteReadServerDenyWorkgroupClient項,設定其DWORD值為1
MSMQ的安全存取控制說明參見:http://msdn.microsoft.com/en-us/library/4108f68e-80f5-40e1-b3df-b713cc4dff79(prot.20).aspx
這樣用戶端就可以讀取伺服器裡的隊列資訊了 當然一般商務邏輯上不這麼做 因為他只負責發送訊息 ,綜上,就是使用訊息佇列 跨伺服器讀寫的 最基本的用法
http://www.cnblogs.com/itjeff/p/6026798.html
static void msgQueue() { System.Messaging.Message msg = null; //對列發送或讀取的實際訊息或資料 MessageQueue mq = null; //接收/發送訊息的MSMQ訊息佇列 try { msg = new Message(); msg.Priority = MessagePriority.Normal;//普通訊息的優先順序 if (!MessageQueue.Exists(@".\Private$\TechRepublic")) { mq = MessageQueue.Create(@".\Private$\TechRepublic"); } //如果不存在則建立它 else { mq = new MessageQueue(@".\Private$\TechRepublic"); } msg.Label = "Test Message"; msg.Body = "this is only a test 01"; mq.Send(msg); Console.WriteLine("message sent"); } catch (System.Messaging.MessageQueueException ex) { Console.WriteLine("MSMQ Error:" + ex.ToString()); } catch (Exception ex) { Console.WriteLine("error:" + ex.ToString()); } finally { mq.Close(); } }
send
遠程:string queuepath = @"FormatName:Direct=TCP:192.168.1.153\private$\queuedemo";
static void msgReceive() { Message msg = null; MessageQueue mq = null; try { mq = new MessageQueue(@".\Private$\TechRepublic"); msg = mq.Receive(new TimeSpan(0, 0, 3));//timespan對象指定異常出現時系統的等待時間。 msg.Formatter = new XmlMessageFormatter(new string[] { "System.String,mscorlib" }); //對象被轉換成字串讀取前面儲存的文本 mq.Receive(); //從隊列中讀取訊息,它的值顯示在控制台中 Console.WriteLine(msg.Label.ToString() + "__" + msg.Body.ToString()); } catch (System.Messaging.MessageQueueException ex) { Console.WriteLine("MSMQ Error" + ex.ToString()); } catch (Exception ex) { Console.WriteLine("Error:" + ex.ToString()); } finally { mq.Close(); } }
Receive
C# 使用訊息佇列,包括遠端存取