用MsmqBinding投送message出現的一個靈異事件 【第二篇】

一線碼農發表於2015-05-24

 

  一直都在用Msmqbinding,也一直忽視了message裡面的內容格式是什麼樣的,這也是微軟給我們高層封裝帶給我們的開發效率,但同時一旦中間出了什麼問題,

就不知道從何查起了。有個需求是這樣的,服務端和客戶端採用離線連線,也就是訊息佇列模式,server接收端在處理訊息的時候,要根據一定的邏輯,如果該訊息不

滿足規則,就把訊息原樣的丟回訊息佇列中,問題就出現在這裡。。。訊息丟進去了,然後,然後就tmd的飛走了!!!先快速的看下程式碼。

 

一:示例程式碼

1.server端

 1         public void Run(Test test)
 2         {
 3             if (test.str.Length % 10 == 0)
 4             {
 5                 //重新丟回訊息佇列
 6                 MessageQueue mq = new MessageQueue(@".\private$\myqueue");
 7                 Message msg = new Message();
 8                 msg.Body = test;
 9                 msg.Formatter = new XmlMessageFormatter(new Type[] { test.GetType() });
10 
11                 mq.Send(msg);
12                 //Environment.Exit(0);
13 
14                 System.Console.WriteLine("已經成功丟回! ,當前執行緒:" + Thread.CurrentThread.ManagedThreadId);
15             }
16             else
17             {
18                 System.Console.WriteLine("已經消費客戶端訊息!");
19             }
20         }

2.服務程式碼

 1         public void Run(Test test)
 2         {
 3             if (test.str.Length % 10 == 0)
 4             {
 5                 //重新丟回訊息佇列
 6                 MessageQueue mq = new MessageQueue(@".\private$\myqueue");
 7                 Message msg = new Message();
 8                 msg.Body = test;
 9                 msg.Formatter = new XmlMessageFormatter(new Type[] { test.GetType() });
10 
11                 mq.Send(msg);
12                 //Environment.Exit(0);
13 
14                 System.Console.WriteLine("已經成功丟回! ,當前執行緒:" + Thread.CurrentThread.ManagedThreadId);
15             }
16             else
17             {
18                 System.Console.WriteLine("已經消費客戶端訊息!");
19             }
20         }

3.client端

 1         static void Main(string[] args)
 2         {
 3             var msmq = new NetMsmqBinding(NetMsmqSecurityMode.None);
 4 
 5             msmq.ExactlyOnce = false;
 6 
 7             ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(msmq,
 8                                                         "net.msmq://localhost/private/myqueue");
 9 
10             var client = factory.CreateChannel();
11 
12             for (int i = 0; i < int.MaxValue; i++)
13             {
14                 var t = new Test() { str = "1111111111" };
15 
16                 client.Run(t);
17                 Console.WriteLine("呼叫第 " + i + "");
18             }
19 
20             var s = 10;
21         }

當時寫的急,也沒關注能不能用MessageQueue將訊息丟回訊息佇列中,然後讓WCF的MsmqBinding去讀取,結果上面的奇葩問題就來了,反正佇列中的資料

一直在減少,但是server端就是沒進來,tmd的wcf卻一個錯誤都不丟擲來,麻蛋。。。為了展示出效果,我特意做成了flash。

從上面的flash中,你可以看到console控制檯已經不在接受訊息了,但是奇怪的是訊息佇列中的資料還是一直在減少。。。。

 

二:懷疑

  從開始在server端將message丟回訊息佇列的時候,我就有一點懷疑,或許這兩種message的內容格式不一樣,wcf在接受的時候應該會報錯,但是tmd的

就是沒有給小爺報錯,現在既然問題來了,我就去比較一下,到底兩種message的格式是什麼樣的,然後我就寫了兩份丟訊息佇列的方法。

 1         static void Main(string[] args)
 2         {
 3             //第一種方式:
 4             var msmq = new NetMsmqBinding(NetMsmqSecurityMode.None);
 5             msmq.ExactlyOnce = false;
 6 
 7             ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(msmq,
 8                                                         "net.msmq://localhost/private/myqueue");
 9             var client = factory.CreateChannel();
10 
11             var t = new Test() { str = "1111111111" };
12 
13             client.Run(t);
14 
15 
16             //第二種方式:
17             MessageQueue mq = new MessageQueue(@".\private$\myqueue");
18             Message msg = new Message();
19             msg.Body = t;
20             msg.Formatter = new XmlMessageFormatter(new Type[] { t.GetType() });
21 
22             mq.Send(msg);
23         }

 

然後我跑去MMC控制檯看一下,果然訊息的大小都不一樣,內容也不一樣。。。真相大白,左邊也不知道是什麼格式,右邊很清楚的看到是xml格式。

 

 

如果文章到這裡的話,說明我也就只能看表面現象,因為剛才我已經提出了一個問題,左邊到底是什麼格式???

 

三:進一步探索

  現在我們知道Msmqbinding使用的是自己獨有格式的訊息body,現在是不是有耐心看看wcf這個底層怎麼寫的呢???我通過一系列的除錯跟蹤,

發現MsmqBinding是先建立一個Msmq的通道棧,可以看到這個channel要傳遞的訊息是soap12協議的,不管是什麼樣的,可以確認的是,訊息傳遞

採用的soap訊息的模式。對吧,如下圖:

 

接下來,這個channel會呼叫wcf自己封裝的訊息佇列MsmqQueue,並且會呼叫其中的send方法,將訊息推送到訊息佇列中,不過要記住,wcf中那

些高層的msmq操作,在底層都是這個類來達到效果的。

 

好了,探索就到這裡為止了,到現在我們起碼知道以下二點訊息了。

 

第一: MessageQueue類投送的訊息一般可以指定xml或者binaray,而WCF中的Msmq中的訊息採用的是soap格式。。。這也是為什麼一個內容小,一個大。

第二: WCF中所有的高層訊息操作,都是建立在自己獨有個MsmqQueue之上,包括send,received方法,只是微軟給我們封裝了而已。

 

相關文章