资源描述
摘要
微软的消息队列中间件技术MSMQ(Microsoft Message Queue)是消息队列中间件中的优秀代表,它是本文重点研究的对象。消息队列中间件技术是一种有着广泛发展前景的技术,也是中间件技术里面发展得最快的。相信随着时间的推移,人们会越来越体会到它在构筑大型分布式应用中的巨大优越性。
本文主要介绍MSMQ在分布式工作流(Workflow)数据交换中的应用,本次毕业设计采用C#编程语言,结合MSMQ消息队列编程技术与业务流程AgilePoint服务平台提供的接口,实现消息队列的部署、消息的发送和接收以及队列的监听,从而达到了对业务流程的管理。把消息队列的应用融入到业务流程管理中,提高了流程运行的效率。
关键词:消息队列中间件,MSMQ,Workflow,分布式网络应用
ABSTRACT
Microsoft Message Queue(MSMQ) is the product from Microsoft Corporation, it is the researching focus in this paper. Message Queue middleware is the technique which will be developed abroad, and that it will be the most popular middleware technique. As time goes on, I believe that people will realize the great advantage of it in building the large distributed applications.
This paper mainly introduces the application of MSMQ in the distributed workflow data exchange. I used C# programming language in my graduation project. As based on MSMQ message queuing programming technique and the interface provided by the business process AgilePoint Service Plateform, I has implement some functionality like the deployment of message queuing sending and receiving messages an monitoring on the queue, then we can manage the business process. The efficiency of the processes running has been improved obviously since the message queuing technique is used in business process management.
Keywords: Message queue middleware, MSMQ, Workflow, Distributed network application.
目录
摘要 I
ABSTRACT II
第1章 引言 1
1.1 背景 1
1.2 研究内容 2
第2章 MSMQ概述 3
2.1 MSMQ的功能 3
2.2 MSMQ的网络拓扑 5
2.3 MSMQ简单工作机制 6
2.3.1 MSMQ的原理 6
2.3.2 消息队列及特点 7
2.4 MSMQ队列类型 8
2.5 MSMQ消息类型 9
第3章 MSMQ编程 10
3.1 MSMQ编程模型 10
3.2 创建队列 11
3.2.1 公共队列 11
3.2.2 私有队列 12
3.3 队列定位 12
3.4 消息发送 13
3.5 消息接受与监听 13
第4章 MSMQ与业务流程管理 19
4.1 业务流程管理简介 19
4.2 MSMQ客户端的功能模块 20
4.3 MSMQ服务器端的功能模块 21
第5章 MSMQ应用业务流程的实现 22
5.1 开发环境 22
5.2 消息的检验 22
5.3 数据传送格式 23
5.4 系统用户界面 23
5.4.1 服务端配置界面 23
5.4.2 客户端界面 33
第6章 结束语 36
致谢 37
参考文献 38
附录 源代码 39
41
第1章 引言
1.1 背景
基于网络的应用程序必须考虑到的一点是网络资源的占有情况。解决该问题可采用三层或多层分布式系统结构[1],将网络资源占用转嫁到分布的各个服务器上。然而,对于网络资源要求较高的系统,如果采用传统的紧密耦合(同步)方式,仍然会出现网络资源紧张的局面[2]。例如:假设有个处理仓库订单的分布式应用程序。首先客户开始一个任务,向仓库提交订单。到达仓库后,系统要读取订单并向仓库管理员显示订单内容。由仓库管理员批准订单,将其标为完成。如果将仓库客户机与之连接,并保持连接,直到订单标记完成,最后返回一个表示成功或失败的信息。现在假设订单到达,而仓库管理员因某种原因不在,这是,客户机和仓库的DCOM组件只好傻等,占用宝贵的网络连接。MSMQ(Microsoft Message Queue,微软消息队列)提供了一个方案和一个相对容易使用的接口,可解决类似的实际业务问题。
在分布式Workflow(工作流)数据交换中,使用MSMQ大大提高整个系统的性能,工作流技术可以实现对业务实例的运行导航和监控,以及任务分配、文档传递等核心功能,是企业信息系统实施的关键[3]。
传统的通讯技术不仅要求发送应用和接受应用同时在线,而且发送者和接受者还要知道相互的程序对程序的调用接口。在实际的情况中,应用程序并不总是同时在线;网络的硬件故障往往不可避免;数据的流量具有突发性,可能造成网络的信息拥塞;各个应用程序之间无法做到实时同步。应用消息队列中间件技术很好的解决了这些问题。总的来讲,消息队列中间件(Message Queue Middleware)的作用体现在两个方面,一时集成大型的分布式应用,二是确保分布式应用之间的一部通讯。MQM在其他传统的通讯方法不能奏效时能够成功,因为它满足三个重要的条件:
1) 发送者和接受者无须同时连接
2) 即使发送者和接受者之间的通讯不是同时发生的,也会有极强的请求和回答传送保障
3) 请求和回答可以通过发送方和接收方之间的路由器进行翻译重新格式化
消息队列中间件技术并不是最新技术,早期,由于没有统一的,适合各种情况和平台的消息队列产品,人们往往自己编写消息队列中间件,这些消息队列中间件虽然可以起到相关的作用,但是它们还是太专业,太原始,费用太高。因此,许多大的公司就开始开发使用于各个情况和平台的消息队列中间件产品,最著名的有IBM的MQSeries和Microsoft的MSMQ,这里主要研究MSMQ的应用。结合.net技术来实现企事业单位的事务流程管理。
1.2 研究内容
研究主要从对消息处理机制入手,对MSMQ的概念、功能、类别、发展趋势等方面做了解。详细阐述MSMQ的使用和管理,以及编程的方面。并结合一个具体的应用来展示消息队列技术在应用程序通讯,数据传输方面的优越性。
拟解决的主要内容:
和大多数Microsoft的技术一样,MSMQ提供了MSMQ对象。编程时用MSMQ对象模型访问它的特性和功能。学会MSMQ对象模型中大约10个对象,重点掌握其中四个对象。对消息队列的数据发送时,研究如何将消息打包;数据接收时,如何与AgilePoint结合。
总的方面来说:
1. 消息发送:客户端将消息发送到服务器端队列中,如果此时服务器关闭或是出现网络故障消息不可到达,那么消息就暂时存储在本地队列中,一旦服务器可用,消息就会自动传送到服务器。
2. 消息流动,消息的检验研究。
3. 服务器端消息接收:服务器端接收消息时,利用MSMQ时间,避免产生服务器端的消息的堆积,消息送到服务器的队列中,应用程序利用MSMQ提供的对象建立时间事件接收器。
4. 事务消息的处理,有内部事务和外部事物
第2章 MSMQ概述
微软消息队列(MicroSoft Message Queue,MSMQ)是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于相连的网络空间中的任一位置。在MSMQ的运作机制中,消息发送程序把要发送的信息放入一个容器(Message)中,然后把它保存到一个系统公用空间的消息队列(Message Queue)内,本地或异地的消息接收程序再从该队列中取出发给它的消息进行处理[4]。
MSMQ是微软的消息队列中间件产品,它是Windows 2003操作系统中消息应用程序的基础,也是用于创建分布式,松散连接的消息通讯应用程序的开发工具。为消息队列开发的应用程序可以将消息发送到队列,这些队列是用来确保消息能够到达目标的临时存储位置。这些应用程序可以通过不同种类的网络进行通讯,也可以与脱机的计算机通讯。消息队列提供了有保障的消息传递、有效的路由、安全性、事务处理支持以及基于优先级的消息传递。用消息队列,最终用户能够在断开连接的网络和计算机之间通讯,而不管网络和计算机的当前状态如何。开发人员可以只关注商业规则,而不必关心网络问题,因为消息队列能够提供有效的网络通讯。
2.1 MSMQ的功能
在Windows2000以前,MSMQ的基本功能如下:
(l) 无连接消息传递
使用存储和转发消息队列,计算机不会受到网络的干扰,也不必建立会话。因为在应用程序级使用无会话模式,所以源计算机和目标计算机不需要支持相同的网络协议。既支持网际协议(IP),也支持Internet数据包交换(IPX)协议。
(2) 消息优先化
消息优先化允许先发送紧急或重要的消息,再发送次重要消息,这样可以保证对关键的应用程序有足够的响应时间,而忽略不太重要的应用程序。
(3) 有保障的消息传递
消息可以存储在基于磁盘的队列中,然后转发以提供有保障的消息传递。
(4) 事务处理消息
使用事务处理功能,可以将一些相关活动在一个事务处理中连接起来,保证消息按顺序传递,保证消息只传递一次并确认消息能够从目标队列成功返回。
(5) 动态队列创建
可以随意创建或更改队列属性,而不影响消息应用程序。
(6) 不同系统的集成
消息队列可以跨越各种硬件平台使用。
(7) 跨平台支持
MSMQ-MQSeries Bridge 扩展了消息队列的功能,提供与IBM MQSeries Version2和Version5平台的无缝、事物处理连通性。消息队列连接器(MQC)可用于将消息队列的功能扩展到其他非Windows的操作系统,包括:UNIX、AS/400、Tandem、Digital VMS、CICS/MVSH和Unisys ClearPath HMP[5]。
在windows 2000之后,MSMQ有了一些新的功能。
(1) Active Directory集成
集成并扩展Active Directory目录服务,以便存储所有配置和状态信息。
(2) 混合模式操作
消息队列可以在混合模式域环境下操作,这意味着在Windows XP下运行的MSMQ 1.0控制器服务器和Windows 2003下运行的消息队列服务器能够进行无缝通讯。
(3) Windows 2003安全集成
消息队列仍然可以通过使用访问控制、审核、加密和身份验证支持保密和安全性,并且能够对嵌入Windows 2003中的新安全功能起到平衡作用,例如Kerberos V5安全协议。
(4) 工作组支持
消息队列可以在Windows 2003工作组中安装和运行,而不是在域中。此外,安装在工作组中的消息队列能够在以后加入到域中,然后再从域分离。Active/active 群集支持。目前消息队列完全支持服务器群集中的active/active操作,这意味着消息队列能够同时在服务器群集中的所有节点上运行。
(5) Microsoft 管理控制台 (MMC) 支持
目前使用MMC控制台中的管理单元管理消息队列。
2.2 MSMQ的网络拓扑
消息队列是由在Windows 2003网络上提供不同功能和连接的计算机所组成的消息基础结构。消息队列既可以在域环境中,也可以在工作组环境中使用。在消息队列环境中,域环境包括提供Active Directory之类目录服务的域控制器,而工作组环境是不提供这种目录服务的任意环境[6]。
1. 域环境
在域环境中,消息队列在windows 2003域控制器上运行,提供对Active Directory的访问。Windows 2003网络中所有域的总和叫做树林。消息队列也可以在混合模式域环境中运行,这个域由在Windows XP上运行的MSMQ 1.0控制器服务器和在Windows 2003上运行的能够互相通讯的消息队列服务器组成。在域环境中,消息队列网络分成不同的Windows 2003站点,这些站点由路由链接互连。站点映射网络的物理结构,而域通常映射单位的逻辑结构。逻辑结构和物理结构是相互独立的,因此一个站点中可能有多个域,也可能在一个域中有多个站点。在消息队列的环境中,站点包含下列内容:
(1) Windows2003域控制器,它在Active Directory目录服务中保留配置和状态信息,并可以使用站点链接在站点之间复制这些信息。Active Directory使用多主机模式,这意味着任何Windows 2003域控制器都可以读取或写入存储在Active Directory中的对象。
(2) 所有Windows 2003 计算机都使用相同的网络协议(一般为IP)。一个站点中使用相同网络协议的任意两台计算机之间都是直接连通的。这种连通性意味着快速而廉价的通讯。
(3) 相关子网的集合,每个子网都有单独的护子网地址。
2. 工作组环境
消息队列可以在不是域的环境下运行,例如工作组或其他不提供目录服务的环境。如果消息队列在工作组中的计算机上运行,则该计算机可以随后加入Windows2003域。相反,消息队列计算机可以是域的一部分,然后再加入工作组。该计算机可以随后重新加入相同的域。但是在非域环境下使用消息队列存在下列限制:
(1) 计算机发送的消息不能由与需要的目标计算机直接连通的消息队列服务器
发送。
(2) 不能访问Active Directory。因此,只能在本地计算机上创建和管理专用队列。不能查看或管理公用队列及Active Directory内的任何其他信息。当然,如果直接连通,则可以将消息发送到专用队列或从中读取消息。
(3) 不能使用内部证书发送经过身份验证的消息;必须使用外部证书代替。
站点1 站点2
MSMQ Server
MSMQ Client
MSMQ Router
MSMQ Server
MSMQ Client
MSMQ Router
MSMQ Server 消息队列服务器 MSMQ Client 消息队列客户机 MSMQ Router 消息队列路由器
图2-1 MSMQ典型网络拓扑
2.3 MSMQ简单工作机制
2.3.1 MSMQ的原理
微软消息队列是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于相连的网络空间中的任一位置。它的实现原理是:消息的发送者把自己想要发送的信息放入一个容器中 (我们称之为Message ),然后把它保存至一个系统公用空间的消息队列 (Message Queue )中;本地或者是异地的消息接收程序再从该队列中取出发给它的消息进行处理。根据MSMQ的工作原理,可以用如图2-2所示来描述分布式应用程序的体系结构。
MSMQ
公用队列
专用队列
传出队列
系统队列
发送进程
接受进程
图2-2 MSMQ应用程序简要结构图
2.3.2 消息队列及特点
在消息传递机制中,有两个比较重要的概念。一个是消息,一个是队列。
消息是由通信的双方所需要传递的信息,它可以是各式各样的媒体,如文本、声音、图像等。消息由正文和一组属性构成。消息正文可包含文本或任何形式的二进制信息,而且可以加密。大多数的消息属性都是由消息队列应用程序通过编程指定的。某些属性,如发送者的安全ID(SID)和消息ID是由消息队列指定的。消息属性不能加密。包括正文和全部指定属性的消息大小不能超过4兆字节(MB)。
消息最终的理解方式,为消息传递的双方事先商定,这样做的好处是,一是相当于对数据进行了简单的加密,二则采用自己定义的格式可以节省通信的传递量。消息可以含有发送和接收者的标识,这样只有指定的用户才能看到只传递给他的信息和返回是否操作成功的回执。消息也可以含有时间戳,以便于接收方对某些与时间相关的应用进行处理。消息还可以含有到期时间,它表明如果在指定时间内消息还未到达则作废,这主要应用与时间性关联较为紧密的应用。
消息队列是发送和接收消息的公用存储空间,它可以存在于内存中或者是物理文件中。消息可以以两种方式发送,即快递方式(Express)和可恢复模式 (Recoverable),它们的区别在于,快递方式为了消息的快速传递,把消息放置于内存中,而不放于物理磁盘上,以获取较高的处理能力;可恢复模式在传送过程的每一步骤中,都把消息写入物理磁盘中,以得到较好的故障恢复能力。消息队列可以放置在发送方、接收方所在的机器上,也可以单独放置在另外一台机器上。正是由于消息队列在放置方式上的灵活性,形成了消息传送机制的可靠性。当保存消息队列的机器发生故障而重新启动以后,以可恢复模式发送的消息可以恢复到故障发生之前的状态,而以快递方式发送的消息则丢失了。另一方面,采用消息传递机制,发送方必要再担心接收方是否启动、是否发生故障非必要因素,只要消息成功发送出去,就可以认为处理完成,而实际上对方可能甚至未曾开机,或者实际完成交易时可能已经是第二天了。
采用MSMQ带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代码,因而大大地提高了事物处理的能力;当信息传送过程中,信息发送机制具有一定功能的故障恢复能力;MSMQ的消息传递机制使得消息通信的双方具有不同的物理平台成为可能。
2.4 MSMQ队列类型
在消息队列环境中,队列是临时存储不同类型消息的地方。有以下的一些类型:
(1) 公共队列
公共队列可以被所有MSMQ客户机访问,由MSMQ服务器在Active Directory中为所有客户显示,它不存在于工作组环境中。
(2) 专用队列
专用队列不在Active Directory中发布而只在包含它们的本地计算机上显示的队列。专用队列只能通过知道队列完整路径名或格式名的消息队列应用程序访问。
(3) 日志队列
存储消息副本的过程叫做记入日志。称作日志消息的这些副本存储在日志队列中。日志有两种类型,即源日志和目标日志,源日志是存储在源计算机上传出的非事务处理消息副本。目标日志是存储在目标计算机上的传入消息副本。
(4) 死信队列
无法传递和过期的非事务处理消息存储在死信队列中。无法传递的和过期的事务处理消息存储事务处理死信队列中。这些消息就存储在消息过期(投递或转发失败)的计算机上的这些队列中。它可以是源计算机、目标计算机或中间的消息队列服务器。
(5) 管理队列
管理队列包括已发送消息的确认消息,发送消息时由发送应用程序通过编程指定。任意有效的非事务处理队列都可指定为管理队列。
(6) 响应队列
响应队列包含接收应用程序发回发送应用程序的响应消息。响应队列由发送应用程序在发送消息时通过编程指定。任意有效的队列都可被指定为响应队列。需要响应队列和管理队列时,根据它们的功能可以合并成一个队列。然而,由于所有的管理队列都必须是非事务处理的,因此该队列将只接受非事务处理消息。
(7) 报告队列
报告队列包含的报告消息指出消息到目的地所采用的路由,还可以包括已发送的测试消息。每台计算机只能有一个报告队列。只有先启动消息路由跟踪,才能创建报告队列。
(8) 系统队列
消息队列可使用最多五个系统队列。所有五个系统队列都作为专用队列执行,这意味着它们不在Active Directory中发布。不能删除系统队列。根据检测方法,分析系统可以采用两种类型的检测技术:误用检测(Misuse Detection)和异常检测(Anomaly Detection)。
2.5 MSMQ消息类型
以下我们根据类别区分消息:
(1) 正常消息
消息队列应用程序所创建的所有消息都是正常消息。正常消息可以发送到公用队列、专用队列、日志队列、死信队列及事务处理队列。正常消息不包含状态信息。这类信息包含在确认消息、报告消息及响应消息中。
(2) 确认消息
确认消息报告正常消息的状态。这些消息不是正的就是负的,并发送到源计算机上的管理队列。正的确认消息表示消息到达目标计算机而且消息是否被读取(由接收应用程序删除)。负的确认消息表示在消息传递到目标计算机之前发生错误,或者表明消息不能读取的原因。
(3) 报告消息
报告消息包括发送到源计算机上的报告队列的测试消息和路由跟踪消息。
(4) 响应消息
响应消息是由接收应用程序发送到发送应用程序指定的响应队列的消息。
第3章 MSMQ编程
3.1 MSMQ编程模型
和大多数Microsoft的技术一样,MSMQ提供了MSMQ对象。编程人员用MSMQ对象模型访问它的特性和功能。MSMQ对象模型中大约有10个对象,但只要利用其中的四个对象就能实现大部分的功能。MSMQ对象中最重要的对象是MSMQQueue,MSMQQueueInfo,MSMQMessage,MSMQEvent.下面对MSMQ对象模型中的对象进行介绍。
(1) MSMQQueueInfo
可以生产和取得一个队列的消息。需要生产这些对象之一才能在程序中建立队列。其中包含Create,Delete,Update,Refresh和Open等方法,用于访问队列。
(2) MSMQQueue
表示队列本身,用于管理发送到队列的消息。它用Receive,ReceiveCurrent, Peek,PeekNext,PeekCurrent,Close和Reset等方法。利用这些方法可以从队列中取出消息或显示消息内容。
(3) MSMQMessage
表示通过MSMQ发送的一个消息,具有多个属性,如消息体Body,到达时间ArrivedTime,属性Priority,BodyLength,MaxTimeToReceive(象有效日期), SendID和SentTime。它只有两个方法。AttachCurrentSecurityContext取得当前安全环境并将其连接到消息中再发送消息,这样可以帮助MSMQ验证消息。Send方法将准备好的消息转发到队列中。
(4) MSMQEvent
表示MSMQ事件,可以是消息到达或错误通知。通过生成和实例化MSMQ Event对象并将其连接到队列,可以在发生这些事件时得到通知并作出响应。消息到达时,触发事件处理器[7],可以处理新消息。
(5) MSMQQuery
定位队列或队列集合,返回MSMQQueueInfos对象。
(6) MSMQQueueInfos
保存MSMQQueueInfo对象集合,由MSMQQuery对象的LookUpQueue方法返回。如果要定位网络上的队列,就要同时用着两个对象。
(7) MSMQCoordinatedTransactionDispenser
取得MSMQTransaction对象。取得之后,可以作为外部事务的一部分接收和发送消息。
(8) MSMQTransactionDispenser
取得MSMQTransaction对象。取得之后,可以作为内部事务的一部分接收和发送消息。
(9) MSMQTransaction
可以作为事务的一部分接收和发送消息,提供方法Abort和Commit,分别取消和完成事务。
(10) MSMQAPPlication
表示应用程序,具有取得计算机标志符的方法。
3.2 创建队列
3.2.1 公共队列
创建队列可以有两种方式,使用管理工具和通过编程。这里介绍如何通过编程来创建一个公共队列。创建一个公共队列主要要用到MessageQueue对象。用C#代码实现如下:
初始化MessageQueue类的一个新实例:
MessageQueue newReceiveQueue = new MessageQueue();
设置队列路径名:
lblRecMQPath.Text = “.\\” + txtRecQueueName.Text;
判断此队列是否存在:
If( MessageQueue.Exists( lblRecMQPath.Text ) )
如果在指定的路径上存在队列,设置newReceiveQueue该实例的path属性。
newReceiveQueue = new
System.Messaging.MessageQueue(lblRecMQPath.Text);
如果在指定的路径上不存在消息队列,则创建一个新的队列:
newReceiveQueue = MessageQueue.Create(lblRecMQPath.Text);
3.2.2 私有队列
当创建一个共有队列时,MSMQ分配给它一个实例ID,并且在活动目录里发布。这允许其它应用通过向路径名属性指定计算机名和队列名来打开这队列,还允许通过使用MSMQQueue对象来执行查询来定位队列。但是,发布一个公共队列需要占用时间和磁盘空间,而且有时这样做也无必要。假如有一个应用,它包含成千上万个需要本地响应队列的独立客户。那么在这种情况下,使用私有队列就很有必要。私有队列在本地创建,并且它们不在活动目录中发布。它们只在所驻留的计算机中发布。
私有队列的创建和公共队列的创建基本相同,只是在路径名前加一个Private,如下所示
初始化MessageQueue类的一个新实例:
MessageQueue newReceiveQueue = new MessageQueue();
设置队列路径名:
lblRecMQPath.Text = “.\\” + MessageQueue.Private + “$\\”
+ txtRecQueueName.Text;
只要MSMQ能够找到其它机器上的私有队列,它们就能够将消息发送到这些队列。这并不象定位公共队列那么简单,因为不能用路径名来打开一个私有队列,它没有在活动目录中发布。
3.3 队列定位
公共队列和私有队列在创建时都由MSMQ分配实例ID。每个队列在它的整个生命周期都携带同一个实例ID。在访问一个队列前,必须由一个队列管理器对实例ID进行解析。MSMQ为一个私有队列和一个共有队列生成实例1D的格式是不同的。共有队列的实例ID就是由MSMQ生成的唯一GUID,而私有队列的实例ID则是由本地队列管理器唯一的GUID和特定计算机队列ID组成。一个私有队列的实例ID如下:
035d92f4-0cc8-44a4-b513-7ce7668f5ef9\00000022
一旦知道了如何生成格式名属性,就可以用如下的代码打开另一台计算机上的私有队列:
String MyFormatName =
“private = 035d92f4-0cc8-44a4-b513-7ce7668f5ef9\00000022”;
MSMQQueueInfo theQI = new MSMQQueueInfo();
theQI.FormatName = MyFormatName;
MSMQQueue theQSend = null;
theQSend = theQI.Open(MQ_SEND_ACCESS, MQ_DENY_NONE);
访问队列的另外一种选择是直接使用格式名,它指定机器地址和目的队列名。如下所示:
theRecMQPath.Text = RecCNorIP.Text + “\\” + MyResponseQueue;
theRecMQPath.Text = “\\” + MyQueue;
当不能使用其它方法时,一般使用直接格式名。例如,为了使以工作组模式建立的两台MSMQ计算机之间能够通讯,就必须使用格式名。
3.4 消息发送
利用COM组件很容易就可以进行消息的发送[8,9]。用C#实现如下:
创建一个消息实例:
System.Messaging.Message mm = new System.Messaging.Message();
创建XMLDocument实例存储要发送的信息,XML格式由发送方和接收方事先约定好:
XmlDocument xmldoc = new XmlDocument();
xmldoc.load(theXMLPath);
Load(xmldoc);
mm.Body = xmldoc.OuterXml;
将消息mm发送到消息队列mq中:
mq.Send(mm);
在MSMQ中,消息体是以字节数组的形式存储。在上例中,消息体是一个XML文档,在许多情况下,消息体中的数据结构比较复杂,需要传递的也是一组参数。这就需要在发方应用中对消息体进行打包。然后在接收方应用中解包。
3.5 消息接受与监听
接收方在接受消息时,并没有约定好时间,大部分处于等待时间。程序中使用MSMQListener时刻监听消息队列。MSMQ中提供了一些重要方法来实现对消息的接受与监听:MessageQueue.BeginReceive,MessageQueue.ReceiveCompleted,MessageQueue.EndReceive。
(1) MessageQueue.BeginReceive:
该方法的功能是:启动一个没有超时设定的一部接受操作。直到队列中出现消息时,才完成此操作。
(2) MessageQueue.ReceiveCompleted:
如果队列中已有消息,将引发ReceiveCompleted事件,此事件通知MessageQueue,再由MessageQueue来处理如何接受消息。在异步处理中,当已从队列中移除某条消息时,使用BeginReceive引发ReceiveCompleted事件。
(3) MessageQueue.EndReceive:
MessageQueue可通过调用EndReceive来访问该消息,了解以上一些重要的方法后,我们可以知道要接收一个消息,首先以接收访问模式打开一个MSMQQueue对象,然后调用BeginReceive方法读取并清除队列中的第一个消息。
监听消息时的具体代码如下:
在监听类的构造函数中,有三个事件,分别是
base.Start += new AppEventHandler(this.OnStart);
base.Stop += new AppEventHandler(this.OnStop);
m_MessageQueue.ReceiveCompleted += new
System.Messaging.ReceiveCompletedEventHandler(
this.MessageReceiveCompleted);
事件OnStart,开始监听工作:
首先,挂载到消息队列中:
XmlNodeList nodesConfig = base.CustomConfiguration;
foreach (XmlNode nodeConfig in nodesConfig)
{
从文档中读取消息队列的路径:
if (nodeConfig.Name == "MessageQueue") {
如果是本机队列,则是以”.”开头
if (nodeConfig.Attributes["ReceiveQueuePath"].Value[0] == '.') {
m_MessageQueue.Path =
nodeConfig.Attributes["ReceiveQueuePath"].Value;
break;
} else {
否则,利用FormatMQPath函数分解出具体的路径格式:
m_MessageQueue.Path = FormatMQPath(
nodeConfig.Attributes["ReceiveQueuePath"].Value);
break;
}
}
}
然后,开始执行BeginReceive来正式启动消息队列的监听:
m_MessageQueue.BeginReceive();
Logger.WriteLine("AgileConnector MSMQListener started.");
} catch (System.Messaging.MessageQueueException ex) {
Logger.WriteLine("MSMQListener.OnStart, {0}", ex.Message);
} catch (Exception ex) {
Logger.WriteLine("MSMQListener.OnStart, {0}", ex.Message);
}
}
事件OnStop,完成消息的接受后,关闭队列:
m_MessageQueue.Close();
m_MessageQueue.Dispose();
m_MessageQueue = null;
事件MessageReceiveCompleted,接受到消息后,启动接受程序,并在接受完消息后删除消息:
try {
调用EndReceive方法来读取消息内容:
System.Messaging.Message m = m_MessageQueue.EndReceive(e.AsyncResult);
m.Formatter = new XmlMessageFormatter(new
String[] { "System.String,mscorlib" });
下面这个方法将执行启动流程的操作,具体过程将在下文继续讲述:
ProcessMessage(m);
} catch (Exception ex) {
string message = ShUtil.GetSoapMessage(ex);
Logger.WriteLine("MSMQListener.MessageReceiveCompleted, {0}", message);
} finally {
完成一个消息的接受和启动流程后,消息队列继续开始监听程序:
m_MessageQueue.BeginReceive();
}
在接收到消息后, ProcessMessage方法要启动流程,其中最重要的部分,代码如下:
private int DoTasks(System.Messaging.Message messa
展开阅读全文