Net使用消息隊列,藉助windows組件來存儲要完成的一系列任務,不用程序使用同一個隊列,方便不同程序之間的數據共享和協作。
隊列分事務性隊列和非事務性隊列,默認創建的是非事務性隊列。那麼什麼是事務性隊列呢?事務性隊列將消息保存在磁盤上,實現了持久化,也就是說當我們關機,斷電後,下次再啓動機器,我們的消息依然保存在隊列裏面,而非事務性隊列則將消息保存在內存中,也就是說我重啓電腦後,隊列裏面的消息將不存在了。
(一) 複雜消息收發(對象)
static void Main(string[] args)
{
const string queueName = @".\Private$\jiyiqin";
MessageQueue mq = null;
if (!MessageQueue.Exists(queueName))// 如果指定的路徑queueName中不存在隊列,那麼在該路徑,即queueName中創建一個消息隊列。jiyiqin就是你想要創建消息隊列的名字
{
mq = MessageQueue.Create(queueName);//創建名稱jiyiqin的消息隊列的實例。
Console.WriteLine("創建消息隊列完成:" + queueName);
}
else //如果消息隊列jiyiqin已經存在,那麼創建該消息隊列的一個實例
{
mq = new MessageQueue(queueName);//創建名稱jiyiqin的消息隊列的實例。
}
mq.SetPermissions("Administrator", MessageQueueAccessRights.FullControl);
mq.SetPermissions("ANONYMOUS LOGON", MessageQueueAccessRights.FullControl);
mq.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);
Message msgTx = new Message();
msgTx.Formatter = new XmlMessageFormatter(new Type[] { typeof(MsgModel) });
msgTx.Body = new MsgModel("1", "消息1");
mq.Send(msgTx);
Console.Write("成功發送消息," + DateTime.Now + "");
if (mq.GetAllMessages().Length > 0)
{
System.Messaging.Message message = mq.Receive(TimeSpan.FromSeconds(5));
if (message != null)
{
message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(MsgModel) });//消息類型轉換
MsgModel msg = (MsgModel)message.Body;
Console.WriteLine(msg.id+msg.Name);
Console.Read();
}
}
}
(二) 本地發/收
//發送
static void Main(string[] args)
{
MessageQueue MSMQ = CreateMessageQueue(@".\private$\jiyiqin");
MSMQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
Console.WriteLine("是否繼續發送消息:Y/N?");
string cmd = Console.ReadLine();
while (cmd.Equals("Y"))
{
Sender(MSMQ);
Console.WriteLine("是否繼續發送消息:Y/N?");
cmd = Console.ReadLine();
}
Console.WriteLine("按任意鍵以停止...");
Console.ReadKey();
}
private static void Sender(MessageQueue MSMQ)
{
try
{
string random = new Random().Next(0,100).ToString();
string obj = string.Format("{0} 發送方:{1}",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), random);
MSMQ.Send(obj, MessageQueueTransactionType.Single);
Console.WriteLine(obj);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("{0} 發送方:{1}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message));
}
}
public static MessageQueue CreateMessageQueue(string path)
{
MessageQueue mq = null;
if (MessageQueue.Exists(path))
{
//存在,創建隊列實例
mq = new MessageQueue(path);
}
else
{
//不存在,創建消息隊列
mq = MessageQueue.Create(path, true);
}
return mq;
}
消息隊列即使接收端沒開啓,消息仍會阻塞在隊列中,等接收端開啓,就可以一條條加載消息。
(三) 異地指定隊列增加消息
異地指定隊列增加消息,我們測試同一局域網內兩臺計算機發/收。
///接收端 ip 192.168.2.240
static void Main(string[] args)
{
MessageQueue MSMQ = CreateMessageQueue(@".\private$\jiyiqin");
MSMQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
Receiver(MSMQ);
}
private static void Receiver(MessageQueue MSMQ)
{
while (true)
{
try
{
Message m = MSMQ.Receive(MessageQueueTransactionType.Single);
Console.WriteLine(string.Format("{0} 接收方:[{1}]",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), m.Body.ToString()));
}
catch (Exception ex)
{
Console.WriteLine(string.Format("{0} 接收方:{1}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message));
}
}
}
public static MessageQueue CreateMessageQueue(string path)
{
MessageQueue mq = null;
if (MessageQueue.Exists(path))
{
mq = new MessageQueue(path);
}
else
{
mq = MessageQueue.Create(path, true);
}
return mq;
}
遠程隊列的路徑格式:string path = @"Formatname:DIRECT=tcp:192.168.2.240\Private$\jiyiqin"; 關鍵字不區分大小寫
MSMQ 判斷隊列是否存在的方法(MessageQueue.Exists(string path))和創建隊列(MessageQueue.Create(string path)),都是不支持遠程隊列的。
1.使用Exists方法會出現錯誤【無法確定具有指定格式名的隊列是否存在】
2.使用Create方法會出現錯誤【無法創建路徑爲 FormatName:DIRECT=tcp:192.168.2.240\Private$\jiyiqin】
3.由於前兩條的限制,如果要訪問遠程專用隊列,則必須保證事先在遠程機器上該隊列是存在的。
static void Main(string[] args)
{
MessageQueue MSMQ = CreateMessageQueue(@"FormatName:Direct=TCP:192.168.2.240\Private$\jiyiqin");
MSMQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
Console.WriteLine("是否繼續發送消息:Y/N?");
string cmd = Console.ReadLine();
while (cmd.Equals("Y"))
{
Sender(MSMQ);
Console.WriteLine("是否繼續發送消息:Y/N?");
cmd = Console.ReadLine();
}
Console.WriteLine("按任意鍵以停止...");
Console.ReadKey();
}
private static void Sender(MessageQueue MSMQ)
{
try
{
string random = new Random().Next(0,100).ToString();
string obj = string.Format("{0} 發送方:{1}",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), random);
MSMQ.Send(obj, MessageQueueTransactionType.Single);
Console.WriteLine(obj);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("{0} 發送方:{1}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message));
}
}
public static MessageQueue CreateMessageQueue(string path)
{
MessageQueue mq = null;
// MessageQueue.Exists(path)會報錯
if (true)
{
//存在,創建隊列實例
mq = new MessageQueue(path);
}
else
{
//不存在,創建消息隊列
mq = MessageQueue.Create(path, true);
}
return mq;
}
當發送消息到遠程隊列時,系統會在本機的傳出隊列下創建一個臨時隊列,每發送一條消息,該消息都會先存在臨時隊列中,這樣做的目的是防止因遠程隊列無法訪問而丟失消息,。
總結
特別注意的是,如果遠程機器不能成功連接,則消息就一直在臨時隊列中存放;如果能成功連接,即使要訪問的隊列並不存在,消息發送程序也不會報錯,並且臨時隊列中的消息會刪除。