去队列里面一直获取消息,一开始想到了两种解决方案:

第一:订阅一次获取一次消息,正常的话每次都能获取到,但是要及时去清理订阅并且时间粒度不好控制

第二:订阅一次,再获取消息这里加死循环,超时MQ已经做了,所以可以不用控制线程等待,获取到消息了以后,直接通过自定义事件的机制去及时处理消息

从最终实验结果来看,第二种是最优的做法,可以做到随时获取到消息,又不占用资源。接下来我把最终的实现代码分享处理,希望对大家有所帮助,有不对的地方,请及时联系我。

订阅主题:

        private IIBMWMQMsgHandler _msgHandler;

        public IBMWMQHelper()
{
_msgHandler = new DefaultIBMWMQMsgHandler();
} public IBMWMQHelper(IIBMWMQMsgHandler msgHandler)
{
_msgHandler = msgHandler;
}
/// <summary>
/// 订阅主题。订阅一次并尝试一直获取消息
/// </summary>
public void SubTopic1(string business, bool isGetMsg = true)
{
IBMWMQEventSource eventSource = new IBMWMQEventSource();
IBMWMQMsgEventListener msgEventListener = new IBMWMQMsgEventListener(_msgHandler);
MQSubscription subs = null;
try
{
//订阅事件
msgEventListener.Subscribe(eventSource);
//MQEnvironment.CCSID = 1381; using (var mqmgr = MQQueueManager.Connect(IBMWMQConfig.QUEUE_MGR_NAME, MQC.MQCO_NONE, IBMWMQConfig.CHANNEL, IBMWMQConfig.CONNECTION_INFO))
{
subs = new MQSubscription(mqmgr);
if (mqmgr.IsConnected)
{
this.TryAdd(business, subs); int option = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_DURABLE | MQC.MQSO_RESUME;
string subName = string.Format(IBMWMQConfig.SUBSCRIPTION_TEMPLATE, business);
string topicName = string.Format(IBMWMQConfig.TOPIC_TEMPLATE, business); try
{
subs.Subscribe(subName, option, topicName);
}
catch (MQException ex)
{
string code = ex.Reason.ToString();
//引发事件
eventSource.RaiseErroeMsgEvent(business, code);
} while (isGetMsg)
{
eventSource.RaiseErroeMsgEvent(business, string.Format("开始尝试获取 {0} 消息...", business));
try
{
MQMessage incoming = new MQMessage()
{
CharacterSet = MQC.CODESET_UTF,
Encoding = MQC.MQENC_NORMAL
};
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.WaitInterval = * ; //MQC.MQWI_UNLIMITED;
gmo.Options |= MQC.MQGMO_WAIT;
gmo.Options |= MQC.MQGMO_SYNCPOINT; subs.Get(incoming, gmo);
string message = incoming.ReadAll(); if (!string.IsNullOrEmpty(message))
{
//引发事件
eventSource.RaiseNewMsgEvent(business, message);
}
}
catch (MQException ex)
{
string code = ex.Reason.ToString();
//引发事件
eventSource.RaiseErroeMsgEvent(business, code);
}
}
}
}
}
catch (MQException e)
{
string code = e.Reason.ToString();
//引发事件
eventSource.RaiseErroeMsgEvent(business, code);
}
finally
{
//if (subs != null)
//{
// subs.Close(MQC.MQCO_REMOVE_SUB, closeSubQueue: true, closeSubQueueOptions: MQC.MQCO_NONE);
//}
}
}

或者使用原生方式:

/// <summary>
/// 订阅主题。订阅一次并尝试一直获取消息(原生)
/// </summary>
/// <param name="business"></param
/// <param name="transportMode"></param>
/// <param name="durability"></param>
public void SubTopic2(string business, string transportMode = "managed", string durability = "durable")
{
Hashtable properties = new Hashtable();
MQTopic topic = null;
IBMWMQEventSource eventSource = new IBMWMQEventSource();
IBMWMQMsgEventListener msgEventListener = new IBMWMQMsgEventListener(_msgHandler); try
{
//订阅事件
msgEventListener.Subscribe(eventSource);
//MQEnvironment.CCSID = 1381; //自动重连
properties.Add(MQC.CONNECT_OPTIONS_PROPERTY, MQC.MQCNO_RECONNECT_Q_MGR);
properties.Add(MQC.HOST_NAME_PROPERTY, IBMWMQConfig.CONNECTION_HOST);
properties.Add(MQC.PORT_PROPERTY, IBMWMQConfig.CONNECTION_PORT);
properties.Add(MQC.CHANNEL_PROPERTY, IBMWMQConfig.CHANNEL); if (transportMode == "managed")
{
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
}
else if (transportMode == "unmanaged")
{
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
} using (var queueManager = new MQQueueManager(IBMWMQConfig.QUEUE_MGR_NAME, properties))
{
if (queueManager.IsConnected)
{
int option4Durable = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_DURABLE | MQC.MQSO_RESUME;//持久化订阅
int option4NotDurable = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING;//非持久化订阅 string subName = string.Format(IBMWMQConfig.SUBSCRIPTION_TEMPLATE, business);
string topicName = string.Format(IBMWMQConfig.TOPIC_TEMPLATE, business); try
{
if (durability == "durable")
{
topic = queueManager.AccessTopic(topicName, null, option4Durable, null, subName);
}
else
{
topic = queueManager.AccessTopic(topicName, null, MQC.MQTOPIC_OPEN_AS_SUBSCRIPTION, option4NotDurable);
} while (true)
{
eventSource.RaiseErroeMsgEvent(business, string.Format("开始尝试获取 {0} 消息...", business));
try
{
MQMessage incoming = new MQMessage()
{
CharacterSet = MQC.CODESET_UTF,
Encoding = MQC.MQENC_NORMAL
};
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.WaitInterval = * ; //MQC.MQWI_UNLIMITED;
gmo.Options |= MQC.MQGMO_WAIT;
gmo.Options |= MQC.MQGMO_SYNCPOINT; topic.Get(incoming, gmo);
string message = incoming.ReadString(incoming.MessageLength); if (!string.IsNullOrEmpty(message))
{
//引发事件
eventSource.RaiseNewMsgEvent(business, message);
}
}
catch (MQException ex)
{
string code = ex.Reason.ToString();
//引发事件
eventSource.RaiseErroeMsgEvent(business, code);
}
}
}
catch (MQException ex)
{
string code = ex.Reason.ToString();
//引发事件
eventSource.RaiseErroeMsgEvent(business, code);
}
}
else
{
eventSource.RaiseErroeMsgEvent(business, "连接队列管理器失败!");
}
}
}
catch (MQException e)
{
string code = e.Reason.ToString();
//引发事件
eventSource.RaiseErroeMsgEvent(business, code);
}
}

接下来开始自定义事件:

定义事件中心:

public class IBMWMQEventSource
{
/// <summary>
/// 新消息处理委托
/// </summary>
/// <param name="business"></param>
/// <param name="msg"></param>
public delegate void NewMsgHandler(string business, string msg);
/// <summary>
/// 新消息处理事件
/// </summary>
public event NewMsgHandler NewMsgEventHandler; /// <summary>
/// 错误消息处理委托
/// </summary>
/// <param name="errorCode"></param>
public delegate void ErrorMsgHandler(string business, string errorCode);
/// <summary>
/// 错误消息处理事件
/// </summary>
public event ErrorMsgHandler ErrorMsgEventHandler; /// <summary>
/// 引发新消息处理事件的方法
/// </summary>
/// <param name="business"></param>
/// <param name="msg"></param>
public void RaiseNewMsgEvent(string business, string msg)
{
if (NewMsgEventHandler != null)
{
NewMsgEventHandler.Invoke(business, msg);
}
} /// <summary>
/// 引发错误消息处理事件的方法
/// </summary>
/// <param name="business"></param>
/// <param name="errorCode"></param>
public void RaiseErroeMsgEvent(string business, string errorCode)
{
if (ErrorMsgEventHandler != null)
{
ErrorMsgEventHandler.Invoke(business, errorCode);
}
}
}

定义事件监听器:

public class IBMWMQMsgEventListener
{
private readonly IIBMWMQMsgHandler _msgHandler; public IBMWMQMsgEventListener(IIBMWMQMsgHandler msgHandler)
{
_msgHandler = msgHandler;
} /// <summary>
/// 订阅事件
/// </summary>
public void Subscribe(IBMWMQEventSource eventSource)
{
eventSource.NewMsgEventHandler += _msgHandler.OnNewMsgHandler;
eventSource.ErrorMsgEventHandler += _msgHandler.OnErrorMsgHandler;
} /// <summary>
/// 取消订阅事件
/// </summary>
public void UnSubscribe(IBMWMQEventSource eventSource)
{
eventSource.NewMsgEventHandler -= _msgHandler.OnNewMsgHandler;
eventSource.ErrorMsgEventHandler -= _msgHandler.OnErrorMsgHandler;
}
}

定义消息处理接口:

public interface IIBMWMQMsgHandler
{
/// <summary>
/// 处理新消息
/// </summary>
/// <param name="business">业务代码</param>
/// <param name="msg">消息包</param>
void OnNewMsgHandler(string business, string msg); /// <summary>
/// 处理错误消息
/// </summary>
/// <param name="business">业务代码</param>
/// <param name="errorCode">错误码</param>
void OnErrorMsgHandler(string business, string errorCode);
}

默认消息处理机制:

public class DefaultIBMWMQMsgHandler : IIBMWMQMsgHandler
{
/// <summary>
/// 处理新消息
/// </summary>
/// <param name="business">业务代码</param>
/// <param name="msg">消息包</param>
public void OnNewMsgHandler(string business, string msg)
{
Trace.WriteLine(string.Format("新消息到达,数据包:{0}", msg));
} /// <summary>
/// 处理错误消息
/// </summary>
/// <param name="business">业务代码</param>
/// <param name="errorCode">错误码</param>
public void OnErrorMsgHandler(string business, string errorCode)
{
Trace.WriteLine(string.Format("处理错误消息,错误码:{0}", errorCode));
}
}

定义消息处理方法:

public class CustomIBMWMQMsgHandler : BaseJobManager, IIBMWMQMsgHandler
{
/// <summary>
/// 消息自定义业务处理
/// </summary>
private static CustomBusinessHandler customBusinessHandler = new CustomBusinessHandler(); /// <summary>
/// 处理新消息
/// </summary>
/// <param name="business"></param>
/// <param name="msg"></param>
public void OnNewMsgHandler(string business, string msg)
{
//获取配置文件
List<JobConfigEntity> configs = InitJobConfig();
string businessName = configs.First(c => c.JobName.Replace("_", "").Contains(business)).Name; switch (business)
{
case IBMWMQConfig.BUSINESS_NAME_ZDFZ09:
msg = customBusinessHandler.RemoveMsgHeader(msg, IBMWMQConfig.BUSINESS_NAME_ZDF_Z09);
customBusinessHandler.DO_ZDF_Z09(business, msg);
break;
case IBMWMQConfig.BUSINESS_NAME_ZAPZ10:
msg = customBusinessHandler.RemoveMsgHeader(msg, IBMWMQConfig.BUSINESS_NAME_ZAP_Z10);
customBusinessHandler.DO_ZAP_Z10(business, msg);
break;
case IBMWMQConfig.BUSINESS_NAME_OULR24:
msg = customBusinessHandler.RemoveMsgHeader(msg, IBMWMQConfig.BUSINESS_NAME_OUL_R24);
customBusinessHandler.DO_OUL_R24(business, msg);
break;
} this.WriteInfo(this.GetType(), string.Format("收到来自{0}的消息,数据包:{1}", businessName, msg));
} /// <summary>
/// 处理错误消息
/// </summary>
/// <param name="business"></param>
/// <param name="errorCode"></param>
public void OnErrorMsgHandler(string business, string errorCode)
{
if (!string.IsNullOrEmpty(errorCode))
{
//获取配置文件
List<JobConfigEntity> configs = InitJobConfig();
string businessName = configs.First(c => c.JobName.Replace("_", "").Contains(business)).Name; //TODO 其他消息内容校验
if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_NO_MSG_AVAILABLE.{0} 无消息({1})。", businessName, errorCode));
}
else if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_UNKNOWN_OBJECT_NAME.{0} 主题不存在({1})。", businessName, errorCode));
}
else if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_SUBSCRIPTION_IN_USE.{0} 主题已被订阅({1})。", businessName, errorCode));
}
else if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_CHANNEL_NOT_AVAILABLE.频道不可用({0})。", errorCode));
}
else if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_HOST_NOT_AVAILABLE.无法连接消息队列主机({0})。", errorCode));
}
else if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_CHANNEL_CONFIG_ERROR.频道配置错误({0})。", errorCode));
}
else if (errorCode.Equals(""))
{
this.WriteInfo(this.GetType(), string.Format("MQRC_UNKNOWN_CHANNEL_NAME.未知频道称({0})。", errorCode));
}
else
{
if (errorCode.Length == )
{
this.WriteInfo(this.GetType(), string.Format("未知错误消息,错误原因编码:{0}。", errorCode));
}
else
{
this.WriteInfo(this.GetType(), string.Format("{0} {1}", businessName, errorCode));
}
}
}
}
}

去掉消息头:

/// <summary>
/// 去掉消息头
/// </summary>
/// <param name="msg"></param>
/// <param name="name"></param>
/// <returns></returns>
public string RemoveMsgHeader(string msg, string name)
{
msg = msg.Trim(); //去掉消息头
int index = msg.IndexOf("<" + name, StringComparison.Ordinal);
if (index > )
{
string temp = msg.Substring(, index);
msg = msg.Substring(index, msg.Length - temp.Length);
msg = msg.Trim();
} return msg;
}

配置信息:

public class IBMWMQConfig
{
/// <summary>
/// MQ主机地址
/// </summary>
private static readonly string CONNECTION_HOST = ConfigHelper.GetValue("IBM_WMQ_CONNECTION_HOST");
/// <summary>
/// 通讯端口
/// </summary>
private const int CONNECTION_PORT = ;
/// <summary>
/// CLIENT_ID
/// </summary>
private const string CLIENT_ID = "";
/// <summary>
/// 通道名称
/// </summary>
public const string CHANNEL = "";
/// <summary>
/// 队列管理器名称
/// </summary>
public const string QUEUE_MGR_NAME = "";
/// <summary>
/// 订阅主题持久化标识,{0}标识具体业务
/// </summary>
public static readonly string SUBSCRIPTION_TEMPLATE = "JMS:" + QUEUE_MGR_NAME + ":" + CLIENT_ID + "_{0}.REQ:{0}.REQ";
/// <summary>
/// 主题名称模板,{0}标识具体业务
/// </summary>
public static readonly string TOPIC_TEMPLATE = "{0}.REQ";
/// <summary>
/// IBM.WMQ连接字符串
/// </summary>
public static readonly string CONNECTION_INFO = string.Format("{0}({1})", CONNECTION_HOST, CONNECTION_PORT); }

调用:

IBMWMQHelper helper = new IBMWMQHelper(new CustomIBMWMQMsgHandler());
helper.SubTopic1(IBMWMQConfig.BUSINESS_NAME_ZAPZ10);

IBM.WMQ订阅主题,连续获取消息解决办法的更多相关文章

  1. IBM.WMQ订阅消息

    网上关于IBM这个消息队列中间件的资料相对比较少,C#相关的资料就更少了,最近因为要对接这个队列中间件,花了不少功夫去搜索.整理各种资料,遇到很多问题,因此记录下来. 1.基于 amqmdnet.dl ...

  2. win32收不到F10按键消息解决办法

    在WM_KEYDOWN中处理F10(VK_F10)消息总是获取不到,后来用spy++监听窗口消息发现按下F10并没有WM_KEYDOWN消息产生,而是产生了WM_SYSKEYDOWN http://b ...

  3. VirtualBox复制的虚拟机无法获取IP解决办法

    自从建立了这个账号后写了一篇,好几年没来了,今天来看看,顺便分享一下. 昨天晚上想玩玩zookeeper集群,在vb里复制了一台主机,可怎么也无法获取IP,经研究,终于还是解决了. 1.复制主机时勾选 ...

  4. asp中 grideview 更新 无法获取值 解决办法

    string str1 = ((TextBox)(GridView1.Rows[e.RowIndex].Cells[7].Controls[0])).Text.ToString().Trim(); 来 ...

  5. Rabbit mq订阅方式获取消息并可设置持久化

    Rabbit 通过方式获取消息:订阅方式事实上是向queue注冊consumer,通过rpc向queue server发送注冊consumer的消息.rabbitMQ Server在收到消息后,依据消 ...

  6. zblog上传安装主题插件不成功的原因和解决办法

    最近有不少zblog用户反映在后台上传安装主题或者插件的时候出现了问题.本文就来尝试说明下这类问题的原因和解决办法. 首先来说说zblog主题或者插件的安装方法,一共有三种方式: 第一种是直接在网站后 ...

  7. [TSM]在调度计划的时候出现 “ANS1125E Unmatched Quotes: 'string' ”错误的替代解决办法

    环境: TSMserver:TSM 6.2.3 for Windows Server 2008 R2 TSMclient: TSM 5.5.0 for CentOS 遇到的故障: ANS1125E U ...

  8. apollo1.7.1初探(二)使用apollo订阅主题,发布主题消息

    一.MQTT协议配置 为了使用MQTT协议,首先使用MQTT3.1协议的客户端连接到Apollo正在监听端口.Apollo会做协议检测,而且自动识别MQTT连接,而且将连接作为MQTT协议处理. 你不 ...

  9. MQTT是IBM开发的一个即时通讯协议,构建于TCP/IP协议上,是物联网IoT的订阅协议,借助消息推送功能,可以更好地实现远程控制

    最近一直做物联网方面的开发,以下内容关于使用MQTT过程中遇到问题的记录以及需要掌握的机制原理,主要讲解理论. 背景 MQTT是IBM开发的一个即时通讯协议.MQTT构建于TCP/IP协议上,面向M2 ...

随机推荐

  1. 4、wordcount程序原理剖析及Spark架构原理

    一.wordcount程序原理深度剖析 二.Spark架构原理 1.

  2. 使用Ajax和一般处理程序实现文件上传与下载

    1.使用HTML的input标签 <input type="file" multiple="multiple" id="file_load&qu ...

  3. 【linux】保存屏幕日志log

    例如: #!/bin/bash #LOG="examples/mnist/lenet_log_mylog" LOG="LOG/log.txt.`date +'%Y-%m- ...

  4. springMVC_注解方式搭建基础环境

    ---恢复内容开始--- 一.jar包环境,web配置文件和Spring-MVC配置文件的,相关的modelAndview 1.配置DispatcherServlet <servlet>  ...

  5. mysql存储引擎介绍,索引

    区别: MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等 ...

  6. eclipse导入maven项目有红叉及pom.xml出错的问题的解决

    导入我们的项目的时候总会出现很多红叉,看着很难受,其实可以解决的(本人使用方法一解决)解决方法:1.先build project,然后右键项目->maven->update project ...

  7. 使用docker运行mysql

    以前开发的时候都是用本地的sqlite开发,但是极少数情况下,sqlite支持的语法发布到服务器上链接mysql会报错. 为了避免这种现象,还是链接本地mysql开发还是更稳定的, 可是开发的项目多了 ...

  8. word excel 未响应

    前几天笔记本突然出现word 一打开就未响应的情况,导致完全无法使用.今天发现 excel 也出现了这种情况.今天终于下定决心解决这个问题. 百度上搜索了很多,找到了很多解决方案.总结如下. 一.禁用 ...

  9. SVG动画示例

    package com.loaderman.customviewdemo; import android.graphics.drawable.Animatable; import android.os ...

  10. opencv之调用摄像头

    基础知识 # cap.set(propId, value) # 设置视频参数: propId - 设置的视频参数, value - 设置的参数值 # cap.isOpened() 返回 true/fa ...