使用C#和IBM MQSeries进行消息发布订阅

使用C#和IBM MQSeries进行消息发布订阅

2011-6-22 创建
2011-8-16 在持久预定后,在关闭时删除预定信息

MQ提供了一个使用C#进行发布订阅到例程MQPubSubSample.cs,首先对其中两个重要的选项进行解释,这两个选项的组合影响了发布订阅中的主题打开方式和消息的订阅接收。

1,托管/非托管 (managed/unmanaged):
 托管使用MQ的动态队列存放订阅信息,非托管由用户指定队列保存


2,持久/非持久(durable/undurable):
 消息订阅分为非持久订阅(non-durable subscription)和持久订阅(durable subscrip-tion),非持久订阅只有当客户端处于激活状态,也就是和MQ队列管理器保持连接状态才能收到

发送到某个主题的消息,而当客户端处于离线状态,这个时间段发到主题的消息将会丢失,永远不会收到。持久订阅时,客户端向MQ队列管理器注册一个识别自己身份的ID,当这个客户端处于离线时,MQ队列管理器会为这个ID 保存所有发送到主题的消息,当客户再次连接时,会根据自己的ID 得到所有当自己处于离线时发送到主题的消息。缺省为非持久。
根据MQ文档,下面4种情形下订阅才会被清除.
1,Connection loss with a non-durable
2,MQCLOSE with MQCO_REMOVE_SUB
3,Administrative DELETE SUB command
4,订阅过期,在设置订阅时指定了订阅期限

 因此总的来说,非持久订阅可以得到在连接期间发布的所有信息,而持久订阅可以得到注册订阅和取消订阅之间发布的所有信息。该持久性与消息的持久性不同,因此与发布者无关。

 

以下代码说明不同的选项使用不同的打开方式

		int openOptionsForGet = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_MANAGED | MQC.MQSO_NON_DURABLE;
                string topicName = "BomStatus";
                string topicObject = null;
                int destType = MQC.MQOT_TOPIC;
                string subName = "WUHAN_" + "Sample1";
                MQTopic destForGet = null;
                MQDestination unmanagedDest = null;

                string unmanagedDestName = DEFAULT_QUEUE;
                int unmanagedDestOpenOptions = MQC.MQOO_INPUT_EXCLUSIVE | MQC.MQOO_FAIL_IF_QUIESCING;

                //Switch flag to test                
                bool managed = true;
                bool durable = true;

                if (managed && durable) //托管持久
                {
                    openOptionsForGet = MQC.MQSO_CREATE | MQC.MQSO_RESUME | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_MANAGED | MQC.MQSO_DURABLE;
                    subName = "WUHAN_" + "Sample1";
                    destForGet = mqQMgr.AccessTopic(topicName, topicObject, openOptionsForGet, null, subName);
		    destForGet.SubscriptionReference.CloseOptions = MQC.MQCO_REMOVE_SUB;
                }
                else if (!managed && durable) //非托管持久
                {
                    openOptionsForGet = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_DURABLE;
                    subName = "WUHAN_" + "Sample2";
                    unmanagedDestName = DEFAULT_QUEUE;
                    unmanagedDestOpenOptions = MQC.MQOO_INPUT_EXCLUSIVE | MQC.MQOO_FAIL_IF_QUIESCING;
                    unmanagedDest = mqQMgr.AccessQueue(unmanagedDestName, unmanagedDestOpenOptions);
                    destForGet = mqQMgr.AccessTopic(unmanagedDest, topicName, topicObject, openOptionsForGet, null, subName);
		    destForGet.SubscriptionReference.CloseOptions = MQC.MQCO_REMOVE_SUB;
                }
                else if (managed && !durable) //托管非持久
                {
                    openOptionsForGet = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_MANAGED | MQC.MQSO_NON_DURABLE;
                    destForGet = mqQMgr.AccessTopic(topicName, topicObject, MQC.MQTOPIC_OPEN_AS_SUBSCRIPTION, openOptionsForGet);
                }
                else if (!managed && !durable) //非托管非持久
                {
                    openOptionsForGet = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_NON_DURABLE;
                    unmanagedDestName = DEFAULT_QUEUE;
                    unmanagedDestOpenOptions = MQC.MQOO_INPUT_EXCLUSIVE | MQC.MQOO_FAIL_IF_QUIESCING;

                    unmanagedDest = mqQMgr.AccessQueue(unmanagedDestName, unmanagedDestOpenOptions);
                    destForGet = mqQMgr.AccessTopic(unmanagedDest, topicName, topicObject, openOptionsForGet);
                }

在设置这些参数后,可以开始发布和订阅

                //发布
                messageForPut = new MQMessage();
                String publishStr = "Publish test data at " + DateTime.Now.ToString();
                messageForPut.WriteString(publishStr);
                mqQMgr.Put(destType, topicObject, null, topicName, messageForPut);
                MessageBox.Show("Publish message success, message is: " + publishStr);


                //订阅
                try
                {
                    messageForGet = new MQMessage();
                    destForGet.Get(messageForGet);
                    String messageDataFromGet = messageForGet.ReadLine();

                    MessageBox.Show("Subscribe message is: " + messageDataFromGet);
                }
                catch (MQException mqE)
                {
                    MessageBox.Show("MQException caught. " + mqE.Message);
                }

 

在使用持久后,MQ资源管理器中预定中出现预定记录,如下图所示:
 

在使用MQ例程时,在持久情况下,第二次打开主题(AccessTopic)时,程序报主题已经存在的错误MQRC_SUB_ALREADY_EXISTS,(REASON CODE 2432)
需要在打开时使用MQC.MQSO_CREATE | MQC.MQSO_RESUME选项避免该错误

用户可以使用下面的用例体会持久和非持久的区别
1,将durable设为false,发布一个新消息,不断开连接接收订阅,应该可以得到该发布消息
2,将durable设为false,发布一个新消息,断开连接后接收订阅,应该收不到该发布消息
3,将durable设为true,发布一个新消息,断开连接后,重新使用相同的SUB进行连接,接收订阅,应该可以得到该发布消息

 

以下是一个简单的 C# WinForm IBM MQ 消息队列监听代码示例: ```csharp using IBM.WMQ; using System; using System.Threading.Tasks; using System.Windows.Forms; namespace IBM_MQ_Listener { public partial class Form1 : Form { private MQQueueManager queueManager; private MQQueue queue; private MQMessage message; private MQGetMessageOptions options; public Form1() { InitializeComponent(); } private async void btnStart_Click(object sender, EventArgs e) { try { // 设置 IBM MQ 连接信息 var properties = new Hashtable(); properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED); properties.Add(MQC.HOST_NAME_PROPERTY, "your.mq.server.ip"); properties.Add(MQC.CHANNEL_PROPERTY, "your.mq.channel"); properties.Add(MQC.PORT_PROPERTY, your.mq.server.port); properties.Add(MQC.USER_ID_PROPERTY, "your.mq.user"); properties.Add(MQC.PASSWORD_PROPERTY, "your.mq.password"); // 连接 IBM MQ 队列管理器 queueManager = new MQQueueManager("your.mq.queue.manager.name", properties); // 打开监听的队列 queue = queueManager.AccessQueue("your.mq.queue.name", MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING); // 初始化消息和获取选项 message = new MQMessage(); options = new MQGetMessageOptions(); // 启动监听循环 await Task.Run(() => { while (true) { try { queue.Get(message, options); // 处理接收到的消息 string msgText = message.ReadString(message.MessageLength); Invoke(new Action(() => { // 在 UI 线程中更新 UI txtReceivedMsg.AppendText(msgText + Environment.NewLine); })); } catch (MQException ex) { if (ex.ReasonCode == MQC.MQRC_NO_MSG_AVAILABLE) { // 没有消息可用,继续循环 continue; } else { // 其他错误,退出循环 throw ex; } } } }); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void btnStop_Click(object sender, EventArgs e) { try { // 关闭队列 if (queue != null) { queue.Close(); } // 断开队列管理器连接 if (queueManager != null) { queueManager.Disconnect(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } ``` 在这个示例中,我们使用 IBM.WMQ 库来连接 IBM MQ 队列管理器,打开监听的队列,接收并处理消息。需要注意的是,IBM.WMQ 库需要安装 IBM MQ 客户端才能正常使用
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值