http://blog.youkuaiyun.com/nyzfl/article/details/1537136
1. 消息队列(Message Queue):
a.
添加System.Messaging.dll.
b.
简介:
利用
MSMQ
(
Microsoft Message Queue
),应用程序开发人员可以通过发送和接收消息方便地与应用程序进行快速可靠的通信。消息处理为您提供了有保障的消息传递和执行许多业务处理的可靠的防故障方法。
MSMQ与XML Web Services和.Net Remoting一样,是一种分布式开发技术。但是在使用XML Web Services或.Net Remoting组件时,Client端需要和Server端实时交换信息,Server需要保持联机。MSMQ则可以在Server离线的情况下工作,将Message临时保存在Client端的消息队列中,以后联机时再发送到Server端处理。
显然,MSMQ不适合于Client需要Server端及时响应的这种情况,MSMQ以异步的方式和Server端交互,不用担心等待Server端的长时间处理过程。
虽然XML Web Services和.Net Remoting都提供了[OneWay]属性来处理异步调用,用来解决Server端长方法调用长时间阻碍Client端。但是不能解决大量Client负载的问题,此时Server接受的请求快于处理请求。
一般情况下,[OneWay]属性不用于专门的消息服务中。
c. 在 .Net 环境下编写简单的 Message Queue 程序
(1)先安装Message Queuing Services
通过Control Panel,“Add/Remove Programs” – “Add/Remove Windows Components”步骤安装MSMQ。
MSMQ可以安装为工作组模式或域模式。如果安装程序没有找到一台运行提供目录服务的消息队列的服务器,则只可以安装为工作组模式,此计算机上的“消息队列”只支持创建专用队列和创建与其他运行“消息队列”的计算机的直接连接。
(2)配置MSMQ
打开Computer Management – Message Queuing,在Private Queues下创建MSMQDemo队列
(3)编写代码-简单演示MSMQ对象
MessageQueue 类是“消息队列”周围的包装。MessageQueue 类提供对“消息队列”队列的引用。可以在 MessageQueue 构造函数中指定一个连接到现有资源的路径,或者可在服务器上创建新队列。在调用 Send、Peek 或 Receive 之前,必须将 MessageQueue 类的新实例与某个现有队列关联。
MessageQueue
支持两种类型的消息检索:同步和异步。同步的
Peek
和
Receive
方法使进程线程用指定的间隔时间等待新消息到达队列。异步的
BeginPeek
和
BeginReceive
方法允许主应用程序任务在消息到达队列之前,在单独的线程中继续执行。这些方法通过使用回调对象和状态对象进行工作,以便在线程之间进行信息通讯。
private
void
btnSendMessage_Click(
object
sender, System.EventArgs e)
{
// Open Queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue( " ./Private$/MSMQDemo " );
// Create Message
System.Messaging.Message message = new System.Messaging.Message();
message.Body = txtMessage.Text.Trim();
message.Formatter = new System.Messaging.XmlMessageFormatter( new Type[]{ typeof ( string )});
// Put Message Into Queue
queue.Send(message);
}
// 同步接收
private void btnReceiveMessage_Click( object sender, System.EventArgs e)
{
try
{
// Open Queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue( " ./Private$/MSMQDemo " );
// Receive message,同步的Receive方法阻塞当前执行线程,直到一个message可以得到
lock (queue)
{
System.Messaging.Message message = queue.Receive( new TimeSpan( 0 , 0 , 0 , 1 ),System.Messaging.MessageQueueTransactionType.Single);
message.Formatter = new System.Messaging.XmlMessageFormatter( new Type[]{ typeof ( string )});
txtReceiveMessage.Text = message.Body.ToString();
}
}
catch (System.Messaging.MessageQueueException ex)
{
// 超时
MessageBox.Show(ex.MessageQueueErrorCode.ToString());
}
}
结束.
// 异步接收
private void Receive1_Click( object sender, System.EventArgs e)
{
System.Messaging.MessageQueue mq1 = new System.Messaging.MessageQueue( " ./Private$/MSMQDemo " );
mq1.ReceiveCompleted += new System.Messaging.ReceiveCompletedEventHandler(ReceiveEvt);
mq1.BeginReceive();
}
private void ReceiveEvt( object source,System.Messaging.ReceiveCompletedEventArgs asyncResult)
{
try
{
System.Messaging.MessageQueue mqReceive = (System.Messaging.MessageQueue)source;
System.Messaging.Message m = mqReceive.EndReceive(asyncResult.AsyncResult);
// 此事m为异步接收到的消息
// 在此插入处理消息的代码
m.Formatter = new System.Messaging.XmlMessageFormatter( new Type[]{ typeof ( string )});
txtReceiveMessage.Text = m.Body.ToString();
mqReceive.BeginReceive(); // 接收下一次事件
}
catch (System.Messaging.MessageQueueException e)
{
System.Windows.Forms.MessageBox.Show(e.MessageQueueErrorCode.ToString());
System.Windows.Forms.MessageBox.Show(e.Message);
}
}
{
// Open Queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue( " ./Private$/MSMQDemo " );
// Create Message
System.Messaging.Message message = new System.Messaging.Message();
message.Body = txtMessage.Text.Trim();
message.Formatter = new System.Messaging.XmlMessageFormatter( new Type[]{ typeof ( string )});
// Put Message Into Queue
queue.Send(message);
}
// 同步接收
private void btnReceiveMessage_Click( object sender, System.EventArgs e)
{
try
{
// Open Queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue( " ./Private$/MSMQDemo " );
// Receive message,同步的Receive方法阻塞当前执行线程,直到一个message可以得到
lock (queue)
{
System.Messaging.Message message = queue.Receive( new TimeSpan( 0 , 0 , 0 , 1 ),System.Messaging.MessageQueueTransactionType.Single);
message.Formatter = new System.Messaging.XmlMessageFormatter( new Type[]{ typeof ( string )});
txtReceiveMessage.Text = message.Body.ToString();
}
}
catch (System.Messaging.MessageQueueException ex)
{
// 超时
MessageBox.Show(ex.MessageQueueErrorCode.ToString());
}
}
结束.
// 异步接收
private void Receive1_Click( object sender, System.EventArgs e)
{
System.Messaging.MessageQueue mq1 = new System.Messaging.MessageQueue( " ./Private$/MSMQDemo " );
mq1.ReceiveCompleted += new System.Messaging.ReceiveCompletedEventHandler(ReceiveEvt);
mq1.BeginReceive();
}
private void ReceiveEvt( object source,System.Messaging.ReceiveCompletedEventArgs asyncResult)
{
try
{
System.Messaging.MessageQueue mqReceive = (System.Messaging.MessageQueue)source;
System.Messaging.Message m = mqReceive.EndReceive(asyncResult.AsyncResult);
// 此事m为异步接收到的消息
// 在此插入处理消息的代码
m.Formatter = new System.Messaging.XmlMessageFormatter( new Type[]{ typeof ( string )});
txtReceiveMessage.Text = m.Body.ToString();
mqReceive.BeginReceive(); // 接收下一次事件
}
catch (System.Messaging.MessageQueueException e)
{
System.Windows.Forms.MessageBox.Show(e.MessageQueueErrorCode.ToString());
System.Windows.Forms.MessageBox.Show(e.Message);
}
}
好处:当第二次点发送消息的时候,自动接收。
D.在后台写的操作类。
/// <summary>
/// 检查队列,如果队列不存在,则建立
/// 队列名称
/// </summary>
/// <param name="path">路径</param>
private static void EnsureQueueExists(string path)
{
if(!System.Messaging.MessageQueue.Exists(path))
{
System.Messaging.MessageQueue.Create(path);
System.Messaging.MessageQueue mqTemp=new System.Messaging.MessageQueue(path);
mqTemp.SetPermissions("Everyone",System.Messaging.MessageQueueAccessRights.FullControl);
///不知道该给什么样的权限好,所以就给了Everone全部权限了,当然大家最好自己控制一下
}
}
/// <summary>
/// 发送对象到队列中
/// 队列名称,因为队列名称在一个应用中应该不改变的,所以大家最好写在配置文件中
/// 要发出去的对象
/// </summary>
/// <param name="QueuePath"></param>
/// <param name="MessageText"></param>
public static void SendQueue(string QueuePath,string MessageText)
{
System.Messaging.MessageQueue mqSend=new System.Messaging.MessageQueue(QueuePath,false);
EnsureQueueExists(QueuePath);
System.Messaging.Message sq=new System.Messaging.Message();
sq.Body=MessageText.Trim();
sq.Formatter=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
mqSend.Send(sq);
}
/// <summary>
/// 从队列中取出对象列表
/// 队列名称
/// 不知道怎么用
/// </summary>
/// <param name="QueuePath"></param>
/// <returns></returns>
public static System.Collections.ArrayList GetMessage(string QueuePath)
{
System.Messaging.Message sq=new System.Messaging.Message();
System.Messaging.MessageQueue mq=new System.Messaging.MessageQueue(QueuePath,false);
mq.Formatter=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
System.Messaging.Message[] arrM=mq.GetAllMessages();
mq.Close();
System.Collections.ArrayList al=new System.Collections.ArrayList();
foreach(System.Messaging.Message m in arrM)
{
sq=m.Body as System.Messaging.Message;
al.Add(sq);
}
return al;
}
/// <summary>
/// 得到计算机消息队列中的数量,做循环进行计数
/// </summary>
/// <param name="QueuePath"></param>
/// <returns></returns>
public static uint Count(string QueuePath)
{
//变量,存放数量
uint numberItems=0;
//连接到队列
System.Messaging.MessageQueue mq=new System.Messaging.MessageQueue(QueuePath);
System.Messaging.MessageEnumerator myEnumerator=mq.GetMessageEnumerator();
while(myEnumerator.MoveNext())
{
numberItems++;
}
return numberItems;
}
/// 检查队列,如果队列不存在,则建立
/// 队列名称
/// </summary>
/// <param name="path">路径</param>
private static void EnsureQueueExists(string path)
{
if(!System.Messaging.MessageQueue.Exists(path))
{
System.Messaging.MessageQueue.Create(path);
System.Messaging.MessageQueue mqTemp=new System.Messaging.MessageQueue(path);
mqTemp.SetPermissions("Everyone",System.Messaging.MessageQueueAccessRights.FullControl);
///不知道该给什么样的权限好,所以就给了Everone全部权限了,当然大家最好自己控制一下
}
}
/// <summary>
/// 发送对象到队列中
/// 队列名称,因为队列名称在一个应用中应该不改变的,所以大家最好写在配置文件中
/// 要发出去的对象
/// </summary>
/// <param name="QueuePath"></param>
/// <param name="MessageText"></param>
public static void SendQueue(string QueuePath,string MessageText)
{
System.Messaging.MessageQueue mqSend=new System.Messaging.MessageQueue(QueuePath,false);
EnsureQueueExists(QueuePath);
System.Messaging.Message sq=new System.Messaging.Message();
sq.Body=MessageText.Trim();
sq.Formatter=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
mqSend.Send(sq);
}
/// <summary>
/// 从队列中取出对象列表
/// 队列名称
/// 不知道怎么用
/// </summary>
/// <param name="QueuePath"></param>
/// <returns></returns>
public static System.Collections.ArrayList GetMessage(string QueuePath)
{
System.Messaging.Message sq=new System.Messaging.Message();
System.Messaging.MessageQueue mq=new System.Messaging.MessageQueue(QueuePath,false);
mq.Formatter=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
System.Messaging.Message[] arrM=mq.GetAllMessages();
mq.Close();
System.Collections.ArrayList al=new System.Collections.ArrayList();
foreach(System.Messaging.Message m in arrM)
{
sq=m.Body as System.Messaging.Message;
al.Add(sq);
}
return al;
}
/// <summary>
/// 得到计算机消息队列中的数量,做循环进行计数
/// </summary>
/// <param name="QueuePath"></param>
/// <returns></returns>
public static uint Count(string QueuePath)
{
//变量,存放数量
uint numberItems=0;
//连接到队列
System.Messaging.MessageQueue mq=new System.Messaging.MessageQueue(QueuePath);
System.Messaging.MessageEnumerator myEnumerator=mq.GetMessageEnumerator();
while(myEnumerator.MoveNext())
{
numberItems++;
}
return numberItems;
}
E.后台写的利用多线程监听的操作类。
private string m_MachineName;
private string m_QueueName;
public bool flag=true;
/// <summary>
/// 重载构造函数,接收必要的队列信息
/// </summary>
/// <param name="MachineName"></param>
/// <param name="QueueName"></param>
public MQListen(string MachineName,string QueueName)
{
m_MachineName=MachineName;
m_QueueName=QueueName;
}
public void Listen()
{
//创建一个MessageQueue对象
System.Messaging.MessageQueue MQ=new System.Messaging.MessageQueue();
//设置MessageQueue对象的路径属性
MQ.Path=m_MachineName+"/private$/"+m_QueueName;
//创建一个Message对象
System.Messaging.Message message=new System.Messaging.Message();
//重复上述步骤,直到收到中止
while(flag)
{
try
{
//休眠以在中断发出时捕捉中断
System.Threading.Thread.Sleep(100);
//将Message对象设置为与接收函数的结果相等
//持续时间(天,时,分钟,秒)
message=MQ.Receive(new TimeSpan(0,0,10,10));
//显示已接受消息的标签
System.Windows.Forms.MessageBox.Show("Label:"+message.Label);
}
catch(System.Threading.ThreadInterruptedException e)
{
//从主线程捕捉ThreadInterrupt并退出
Console.WriteLine("Exiting Thread");
message.Dispose();
MQ.Dispose();
break;
}
catch(Exception GenericException)
{
// 捕捉接收过程中抛出的所有异常。
Console.WriteLine(GenericException.Message);
}
}
}
启动和终止线程操作同步消息队列:
简单:
启动: MultiThreadedMQListener.MQListen objMQListen=new WinFormExample1._0320.MultiThreadedMQListener.MQListen(".","MSMQDemo");
System.Threading.Thread thread=new System.Threading.Thread(new System.Threading.ThreadStart (objMQListen.Listen));
t.Start();
终止: MultiThreadedMQListener.MQListen objMQListen=new WinFormExample1._0320.MultiThreadedMQListener.MQListen(".","MSMQDemo");
objMQListen.flag=false;
复杂(线程池):
private void StartThreads()
{
int LoopCounter;//线程计数
StopListeningFlag=false;// 跟踪辅助线程是否应当终止的标志。
//将一个包含 5 个线程的数组声明为辅助线程。
Thread[] ThreadArray=new Thread[5];
//声明包含辅助线程的所有代码的类。
MQListen objMQListen=new MQListen(server.Text,Queue.Text);
for(LoopCounter=0;LoopCounter<ThreadArray.Length;LoopCounter++)
{
//创建一个 Thread 对象。
ThreadArray[LoopCounter]=new Thread(new ThreadStart(objMQListen.Listen));
//启动线程将调用 ThreadStart 委托。
ThreadArray[LoopCounter].Start();
}
statusBar1.Text=LoopCounter.ToString()+" listener threads started";
while(!StopListeningFlag)
{
//等待用户按下停止按钮。
//在等待过程中,让系统处理其他事件。
System.Windows.Forms.Application.DoEvents();
}
statusBar1.Text="Stop request received,stopping threads";
//向每个线程发送一个中断请求。
for(LoopCounter=0;LoopCounter<ThreadArray.Length;LoopCounter++)
{
ThreadArray[LoopCounter].Interrupt();
}
statusBar1.Text="All Threads have been Stopped";
}
private bool StopListeningFlag=false;
private void start_Click(object sender, System.EventArgs e)
{
statusBar1.Text="Starting Threads";
StartThreads();
}
private void stop_Click(object sender, System.EventArgs e)
{
StopListeningFlag=true ;
}
private string m_QueueName;
public bool flag=true;
/// <summary>
/// 重载构造函数,接收必要的队列信息
/// </summary>
/// <param name="MachineName"></param>
/// <param name="QueueName"></param>
public MQListen(string MachineName,string QueueName)
{
m_MachineName=MachineName;
m_QueueName=QueueName;
}
public void Listen()
{
//创建一个MessageQueue对象
System.Messaging.MessageQueue MQ=new System.Messaging.MessageQueue();
//设置MessageQueue对象的路径属性
MQ.Path=m_MachineName+"/private$/"+m_QueueName;
//创建一个Message对象
System.Messaging.Message message=new System.Messaging.Message();
//重复上述步骤,直到收到中止
while(flag)
{
try
{
//休眠以在中断发出时捕捉中断
System.Threading.Thread.Sleep(100);
//将Message对象设置为与接收函数的结果相等
//持续时间(天,时,分钟,秒)
message=MQ.Receive(new TimeSpan(0,0,10,10));
//显示已接受消息的标签
System.Windows.Forms.MessageBox.Show("Label:"+message.Label);
}
catch(System.Threading.ThreadInterruptedException e)
{
//从主线程捕捉ThreadInterrupt并退出
Console.WriteLine("Exiting Thread");
message.Dispose();
MQ.Dispose();
break;
}
catch(Exception GenericException)
{
// 捕捉接收过程中抛出的所有异常。
Console.WriteLine(GenericException.Message);
}
}
}
启动和终止线程操作同步消息队列:
简单:
启动: MultiThreadedMQListener.MQListen objMQListen=new WinFormExample1._0320.MultiThreadedMQListener.MQListen(".","MSMQDemo");
System.Threading.Thread thread=new System.Threading.Thread(new System.Threading.ThreadStart (objMQListen.Listen));
t.Start();
终止: MultiThreadedMQListener.MQListen objMQListen=new WinFormExample1._0320.MultiThreadedMQListener.MQListen(".","MSMQDemo");
objMQListen.flag=false;
复杂(线程池):
private void StartThreads()
{
int LoopCounter;//线程计数
StopListeningFlag=false;// 跟踪辅助线程是否应当终止的标志。
//将一个包含 5 个线程的数组声明为辅助线程。
Thread[] ThreadArray=new Thread[5];
//声明包含辅助线程的所有代码的类。
MQListen objMQListen=new MQListen(server.Text,Queue.Text);
for(LoopCounter=0;LoopCounter<ThreadArray.Length;LoopCounter++)
{
//创建一个 Thread 对象。
ThreadArray[LoopCounter]=new Thread(new ThreadStart(objMQListen.Listen));
//启动线程将调用 ThreadStart 委托。
ThreadArray[LoopCounter].Start();
}
statusBar1.Text=LoopCounter.ToString()+" listener threads started";
while(!StopListeningFlag)
{
//等待用户按下停止按钮。
//在等待过程中,让系统处理其他事件。
System.Windows.Forms.Application.DoEvents();
}
statusBar1.Text="Stop request received,stopping threads";
//向每个线程发送一个中断请求。
for(LoopCounter=0;LoopCounter<ThreadArray.Length;LoopCounter++)
{
ThreadArray[LoopCounter].Interrupt();
}
statusBar1.Text="All Threads have been Stopped";
}
private bool StopListeningFlag=false;
private void start_Click(object sender, System.EventArgs e)
{
statusBar1.Text="Starting Threads";
StartThreads();
}
private void stop_Click(object sender, System.EventArgs e)
{
StopListeningFlag=true ;
}
异步操作消息队列:
先声明一个
System.Threading.ManualResetEvent socketEvent=new System.Threading.ManualResetEvent(false);
先socketEvent.Reset();
BeginReceive();监听;
然后socketEvent.WaitOne();
回调函数中
先socketEvent.Set(); 然后使用EndReceive ()来完成数据报的接收