本章我们来了解下MSMQ的基本概念和开发过程。
MSMQ全称MicroSoft Message Queue,微软消息队列,是在多个不同应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于相连的网络空间的任一位置。
它的实现原理是:消息的发送者要把自己想要发送的信息放入一个容器中(我们称之为Message),然后把它保存至一个系统公用空间的消息队列(Message Queue)中,本地或者是异地的消息接收程序再从该队列中取出发给它的消息进行处理。
其中两个重要的概念。一个是消息Message,一个是队列Queue。
消息可以是各式各样的媒体,如文本、声音、图像等等。消息的最终理解方式,为消息传递的双方事先商定,这样的好处是,一是相当于对数据进行了简单的加密,二则采用自己定义的格式可以节省通信的传递量。消息可以含有发送和接受者的标识,只有指定的用户才能看到回执。
时间戳,便于接受方对某些与时间相关的应用进行处理。截止时间,指定时间内消息还到达则作废。
队列的类型主要包括以下几种:
“公共队列”在整个消息队列网络中复制,并且有可能由网络连接的所有站点访问。
“专用队列”不在整个网络中发布。相反,他们仅在所驻留的本地计算机上可用。专用队列只能由知道队列的完整路径名或标签的应用程序访问。
“管理队列”包含确认在给定“消息队列”网络中发送的消息回执的消息。指定希望MessageQueue组件使用的管理队列(如果有的话)
“响应队列”包含目标应用程序接收消息时返回给发送应用程序的响应消息。指定希望MessageQueue组件使用的响应队列(如果有的话)。
消息队列是发送和接收消息的公用存储空间,它可以存在于内存中或者是物理文件中。消息可以以两种方式发送,即快递方式(express)和可恢复模式(recoverable),它们的区别在于,快递方式为了消息放置于内存中,可恢复模式放于物理磁盘上。
消息队列的优缺点
优点:稳定、消息优先级、脱机能力以及安全性,有保障的消息传递和执行许多业务处理的可靠地仿故障机制。
缺点:MSMQ不适合客户端需要服务器端实时交互情况,大量请求时候,响应延迟。
首先我们先要安装消息队列服务器并且开启消息队列服务,以下是代码实现:
首先,创建一个控制台项目(当然你也可以创建Web或者Winform应用程序).添加项目引用System.Messaging,因为消息队列相关的类库全部封装在System.Messaging.dll程序集里了.下面我们就来写自己的代码.
using System; using System.Collections.Generic; using System.Linq; using System.Messaging; using System.Text; using System.Threading.Tasks; using Model; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string msmqName = @".\YXLMSMQ"; string privateMsmqName = @".\Private$\YXLMSMQ"; //你在创建公有队列,而你的机器不属于任何域。一般工作组安装的计算机只能创建私有队列。 //if (!MessageQueue.Exists(msmqName))//判断此路径下是否已经有该队列 //{ // using (MessageQueue mq = MessageQueue.Create(msmqName)) // { // mq.Label = "YXLPublicQueue"; //设置队列标签 // Console.WriteLine(mq.Path); //队列路径 // Console.WriteLine(mq.QueueName); // mq.Send("Send To MSMQ Object", "YXLMSMQLabel");//发送消息 // } //} //创建私有消息队列 if (!MessageQueue.Exists(privateMsmqName))//判断此路径下是否已经有该队列 { using (MessageQueue mq = MessageQueue.Create(privateMsmqName)) { mq.Label = "YXLPrivateQueue"; //设置队列标签 Console.WriteLine(mq.Path); //队列路径 Console.WriteLine(mq.QueueName); mq.Send("Send To Private MSMQ Object", "YXLMSMQLabel1");//发送消息 } } //获取公共消息队列并且发送消息 //foreach (MessageQueue mq in MessageQueue.GetPublicQueues()) //{ // mq.Send("Sending MSMQ public message" + DateTime.Now.ToLongDateString(), "YXLMSMQLabel");//发送公共消息 // Console.WriteLine(mq.Path); //} //找到私有的消息队列并且发送消息 if (MessageQueue.Exists(privateMsmqName))//判断此路径下是否已经有该队列 { using (MessageQueue mq = new MessageQueue(privateMsmqName)) { //mq.Send("Send MSMQ Private message" + DateTime.Now.ToLongDateString(), "YXLMSMQLabel2"); //发送复杂类型 mq.Send(new User() {Id = 1, Name = "张三"}, "YXLMSMQLabelUser"); //发送消息到私有队列里 Console.WriteLine(mq.Path); } } } } }
比较重要的类就是MessageQueue,这行代码创建消息队列 MessageQueue mq = MessageQueue.Create(privateMsmqName),参数是存放消息队列的位置.这个基本就完成了创建和发送消息的主程序.下面我们来建立一个客户端,来访问消息队列,获取消息,同样建立一个控制台应用程序,添加引用和代码:
using System; using System.Collections.Generic; using System.Linq; using System.Messaging; using System.Text; using System.Threading.Tasks; using Model; namespace ConsoleApplicationMSMQClient { class Program { static void Main(string[] args) { string privateMsmqName = @".\Private$\YXLMSMQ"; //找到私有的消息队列并且发送消息 if (MessageQueue.Exists(privateMsmqName))//判断此路径下是否已经有该队列 { using (MessageQueue mq = new MessageQueue(privateMsmqName)) { //mq.Formatter = new XmlMessageFormatter(new string[]{"System.String"});//设置消息队列格式化器 //Console.WriteLine(message.Body); mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(User) }); Message message = mq.Receive(); User user = message.Body as User; Console.WriteLine(user.Id+"-------"+user.Name); } } } } }
消息接收同样需要实例化一个消息队列对象, using(MessageQueue mq = new MessageQueue(privateMsmqName))负责创建消息队列对象.其次 mq.Formatter = new XmlMessageFormatter(new string[] { "System.String" })这行代码负责设置消息队列的格式化器,因为消息的传递过程中存在格式化的问题.我们接收消息的时候必须指定消息队列的格式化属性Formatter,队列才能接受消息.XmlMessageFormatter的作用是进行消息的XML串行化.BinaryMessageFormatter则把消息格式化为二进制数据进行传输.ActiveXMessageFormatter把消息同样进行二进制格式化,区别是可以使用COM读取队列中的消息.
当然消息队列还可以发送复杂的对象,前提是这个对象要可串行化,具体的格式取决与队列的格式化器设置.此外消息队列还支持事务队列来确保消息只发送一次和发送的顺序.