MSMQ

来源:互联网 发布:java初学者看什么书比较好 编辑:程序博客网 时间:2024/04/29 16:12

MSMQ

 MSMQ(全称Microsoft Message Queue,微软消息队列)是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于相连的网络空间中的任一位置。它的实现原理是:消息的发送者把自己想要发送的信息放入一个容器中(我们称之为Message),然后把它保存至一个系统公用空间的消息队列(Message Queue)中;本地或者是异地的消息接收程序再从该队列中取出发给它的消息进行处理。

Message Queuing(MSMQ) technology enables applications running at different times to communicate across heterogeneous networks and systems that may be temporarily offline. Applications send messages to queues and read messages from queues. The following illustration shows how a queue can hold messages that are generated by multiple sending applications and read by multiple receiving applications.

Where Applicable

Message Queuing provides guaranteed message delivery, efficient routing, security, and priority-based messaging.

 

在消息传递机制中, 有两个比较重要的概念。 一个是消息, 一个是队列。

消息是由通信的双方所需要传递的信息,它可以是各式各样的媒体,如文本、声音、图象等等。消息最终的理解方式,为消息传递的双方事先商定,这样做的好处是,一是相当于对数据进行了简单的加密,二则采用自己定义的格式可以节省通信的传递量。消息可以含有发送和接收者的标识,这样只有指定的用户才能看到只传递给他的信息和返回是否操作成功的回执。消息也可以含有时间戳,以便于接收方对某些与时间相关的应用进行处理。消息还可以含有到期时间,它表明如果在指定时间内消息还未到达则作废,这主要应用与时间性关联较为紧密的应用。

消息队列是发送和接收消息的公用存储空间,它可以存在于内存中或者是物理文件中。消息可以以两种方式发送,即快递方式(express)和可恢复模式(recoverable),它们的区别在于,快递方式为了消息的快速传递,把消息放置于内存中,而不放于物理磁盘上,以获取较高的处理能力;可恢复模式在传送过程的每一步骤中,都把消息写入物理磁盘中,以得到较好的故障恢复能力。消息队列可以放置在发送方、接收方所在的机器上,也可以单独放置在另外一台机器上。正是由于消息队列在放置方式上的灵活性,形成了消息传送递机制的可靠性。当保存消息队列的机器发生故障而重新启动以后,以可恢复模式发送的消息可以恢复到故障发生之前的状态,而以快递方式发送的消息则丢失了。另一方面,采用消息传递机制,发送方不必要再担心接收方是否启动、是否发生故障等等非必要因素,只要消息成功发送出去,就可以认为处理完成,而实际上对方可能甚至未曾开机,或者实际完成交易时可能已经是第二天了。

”消息队列“是Microsoft的消息处理技术,它在任何安装了Microsoft Windows的计算机组合中,为任何应用程序提供消息处理和消息队列功能,无论这些计算机是否在同一个网络上或者是否同时联机。

”消息队列网络“是能够相互间来回发送消息的任何一组计算机。网络中的不同计算机在确保消息顺利处理的过程中扮演不同的角色。它们中有些提供路由信息以确定如何发送消息,有些保存整个网络的重要信息,而有些只是发送和接受消息。

“消息队列“安装期间,管理员确定哪些服务器可以互相通信,并设置特定服务器的特殊角色。构成此”消息队列“网络的计算机称为”站点“,它们之间通过”站点链接“互相连接。每个站点链接都有一个关联的”开销“,它由管理员确定,指示了经过此站点链接传递消息的频率。

”消息队列“管理员还可在网络中设置一台或多台作为”路由服务器“的计算机。路由服务器查看各站点链接的开销,确定经过多个站点传递消息的最快和最有效的方法,以此决定如何传递消息。

队列类型(Queue Type)

有两种主要的队列类型:系统队列;应用程序队应用程序或管理员创建的队列称作应用程序队列。消息队列创建的队列称作系统队列

系统队列消息队列创建系统队列。应用程序可以读取系统队列中的消息,但无法为其寻址消息

应用程序队可能是以下任何一种队列:

·        目标队列,包括:公用队列和专用队列

                “公共队列“在整个”消息队列“网络中复制,并且有可能(依据权限)由网络连接的所有站点访问。

                “专用队列“不在整个网络中发布。相反,它们仅在所驻留的本地计算机上可用。专用队列只能由知道队列的完整路径名或标签的应用程序访问。

·        管理队列

管理队列是应用程序生成的队列。这些队列用于存储系统生成的消息队列或连接器应用程序创建的否定和肯定确认消息。它们由发送应用程序以编程方式在初始消息中指定。任何可用的非事务性队列都可以指定为管理队列。管理队列不包含存储在内部专用队列中的管理消息。

·        响应队列

响应队列也是应用程序生成的队列。它们用于存储应用程序生成的响应消息,这些响应消息通常由从队列读取消息的应用程序返回。响应队列由发送应用程序在消息发送时以编程方式指定。任何可用的队列都可以指定为响应队列。

·        报告队列

报告队列是应用程序生成的队列,用于存储消息队列或连接器应用程序在发送应用程序请求跟踪时生成的报告消息。每台计算机只能有一个报告队列。

https://msdn.microsoft.com/zh-cn/library/windows/apps/cc772532.aspx

MSDN)

采用MSMQ带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代码,因而大大地提高了事物处理的能力;当信息传送过程中,信息发送机制具有一定功能的故障恢复能力;MSMQ的消息传递机制使得消息通信的双方具有不同的物理平台成为可能。

缺点: MSMQ不适合于Client需要Server端实时交互情况。大量请求时候,响应延迟。

在微软的.net平台上利用其提供的MSMQ功能,可以轻松创建或者删除消息队列、发送或者接收消息、甚至于对消息队列进行管理。 消息队列相关的类库全部封装在System.Messaging.dll程序集里了。其中MessageQueue类提供对“消息队列”队列的应用。可以在MessageQueue构造函数中指定一个连接到现有资源的路径,或者可以直接在服务器上创建新队列。


Demo以及示例代码如下所示:

 

using System;using System.Linq;using System.Windows.Forms;using System.Messaging;namespace MSMQ_Demo{    public partial class Form1 : Form    {        private string publicQueuePath = @".\PublicMSMQForDemo";        private string privateQueuePath = @".\Private$\PrivateMSMQDemo";                public Form1()        {            InitializeComponent();        }        private void btnSendMessage_Click(object sender, EventArgs e)        {            bool bPublicQueueExist = System.Messaging.MessageQueue.Exists(publicQueuePath);            if (!bPublicQueueExist)            {                using (MessageQueue pulicQueue = MessageQueue.Create(publicQueuePath))                {                    pulicQueue.Send("From one new Public Queue");                }            }            else            {                using (MessageQueue publicQueue = new MessageQueue(publicQueuePath))                {                    publicQueue.Send("From one existing Public Queue");                }            }            bool bPrivateQueueExist = System.Messaging.MessageQueue.Exists(privateQueuePath);            if(!bPrivateQueueExist)            {                using (MessageQueue privateQueue = MessageQueue.Create(privateQueuePath))                {                    System.Messaging.Message message = new System.Messaging.Message();                    message.Body = "From one new Private Queue";                    message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) });                    privateQueue.Send(message);                }            }            else            {                using (MessageQueue privateQueue = new MessageQueue(privateQueuePath))                {                    privateQueue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) });                    System.Messaging.Message message = new System.Messaging.Message();                    message.Body = txtMessage.Text.Trim();                    privateQueue.Send(message);                }            }            foreach (MessageQueue mq in MessageQueue.GetPublicQueues())            {                mq.Send("Sending MSMQ public message", "From Nick");            }            if (System.Messaging.MessageQueue.Exists(privateQueuePath))            {                MessageQueue mq = new MessageQueue(privateQueuePath);                mq.Send("Sending MSMQ private message again", "From Nick");            }                    }        private void btnReceiveMessage_Click(object sender, EventArgs e)        {            bool bPublicQueueExist = System.Messaging.MessageQueue.Exists(publicQueuePath);            if(bPublicQueueExist)            {                using(MessageQueue publicQueue = new MessageQueue(publicQueuePath))                {                    publicQueue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) });                    int count = publicQueue.GetAllMessages().Count();                    while(count-- > 0)                    {                        System.Messaging.Message msg = publicQueue.Receive();                        txtReceiveMessage.Text += (msg.Body.ToString() + "\n");                    }                                    }            }            bool bPrivateQueueExist = System.Messaging.MessageQueue.Exists(privateQueuePath);            if(bPrivateQueueExist)            {                using(MessageQueue privateQueue = new MessageQueue(privateQueuePath))                {                    privateQueue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) });                    int count = privateQueue.GetAllMessages().Count();                    while (count-- > 0)                    {                        System.Messaging.Message msg = privateQueue.Receive();                        txtReceiveMessage.Text += (msg.Body.ToString() + "\n");                    }                 }            }        }    }}

 消息接收同样需要实例化一个消息队列对象, using(MessageQueue mq = new MessageQueue("...")负责创建消息队列对象.其次 mq.Formatter = new XmlMessageFormatter(...)这行代码负责设置消息队列的格式化器,因为消息的传递过程中存在格式化的问题.我们接收消息的时候必须指定消息队列的格式化属性Formatter,队列才能接受消息。

XmlMessageFormatter的作用是进行消息的XML串行化。

BinaryMessageFormatter则把消息格式化为二进制数据进行传输。

ActiveXMessageFormatter把消息同样进行二进制格式化,区别是可以使用COM读取队列中的消息。

当然消息队列还可以发送复杂的对象,前提是这个对象要可串行化,具体的格式取决与队列的格式化器设置。此外消息队列还支持事务队列来确保消息只发送一次和发送的顺序。


 

0 0