关于访问MSMQ远端私有队列的一点经验

这里应该将私有队列称做“专用队列”好像更贴切一些了,O(∩_∩)O

可以访问远程主机的MSMQ的私有队列的,这个是毋庸置疑的,但需要说明的是不能通过代码创建私有队列,关于这一点,我也不知道为什么?

下面说说我的经验

1、首先要保证远端的主机和本地机器同时加入到了同一个域中

2、要通过管理工具在远端主机中创建私有的队列,例如 192.168.117.47\Private$\MyPath,可以在创建时指定是否启用事务

3、在本地无法得到远端是否存在指定的私有队列,也无法得到指定的私有队列是否已经启用了事务,因此在编码时,最好能明确的知道远端已经创建了这个私有队列,并且这个私有队列是否已经启用了事务

4、下面给出远端私有队列的格式

如果是 IP 地址的形式,请使用 "FormatName:DIRECT=TCP:" + 远端IP + @"\private$" + @"\" + 私有队列的路径名称

如果是机器名的方式,请使用 "FormatName:DIRECT=OS:" +远端的主机名 +    @"\private$" + @"\" + 私有队列的路径名称

5、要保证本机和远端的主机使用同样的域账户登录,最好这个账户也是本机及远端机的系统管理员组成员

发送消息

public bool SendMessage(string path, object source, bool transactional = false){

// 注意路径的格式见本日志(一)的部分

if (!string.IsNullOrWhiteSpace(path) && source != null)

{

try

{

using (MessageQueue mqSender =  new  MessageQueue  (path))

{

mqSender.MessageReadPropertyFilter.Body = true;

mqSender.MessageReadPropertyFilter.AppSpecific = true;

mqSender.MessageReadPropertyFilter.Priority = true;

mqSender.MessageReadPropertyFilter.Recoverable = true; // 防止重启主机时丢失消息

mqSender.Formatter = new XmlMessageFormatter(new Type[] { source.GetType() });

if ( transactional   == true)

{

using (MessageQueueTransaction tran = new MessageQueueTransaction())

{

tran.Begin();

mqSender.Send(source, tran);

tran.Commit();

}

}

else

mqSender.Send(source);

mqSender.Close();

}

return true;

}

catch (MessageQueueException ex)

{

Console.Write(ex);

}

catch (Exception ex)

{

Console.Write(ex);

}

}

return false;

}

接收消息

public static T GetMessage<T>(string path, bool isDeleteMessage = true, bool transactional = false)

{

T result = default(T);

try

{

using (MessageQueue mqReceiver = new MessageQueue(path))

{

mqReceiver.MessageReadPropertyFilter.Body = true;

mqReceiver.MessageReadPropertyFilter.AppSpecific = true;

mqReceiver.MessageReadPropertyFilter.Priority = true;

mqReceiver.MessageReadPropertyFilter.Recoverable = true; // 防止重启主机时丢失消息

mqReceiver.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });

Message message = null;

if ( transactional  == true)

{

if (isDeleteMessage == true)

{

using (MessageQueueTransaction tran = new MessageQueueTransaction())

{

tran.Begin();

Console.WriteLine("等待接收......");

message = mqReceiver.Receive(tran);

Console.WriteLine("接到了");

tran.Commit();

}

}

else

message = mqReceiver.Peek();

}

else

{

if (isDeleteMessage)

{

Console.WriteLine("等待接收......");

message = mqReceiver.Receive();

Console.WriteLine("接到了");

}

else

message = mqReceiver.Peek();

}

if (message != null)

result = (T)message.Body;

mqReceiver.Close();

}

}

catch (MessageQueueException ex)

{

Console.Write(ex);

}

catch (Exception ex)

{

Console.Write(ex);

}

return result;

}

申:

以下代码在调试远端的主机时会出现异常

bool b = MessageQueue.Exists(path); // 按说应该不会,但是我的机器调试时总出错,不知道为什么?

MessageQuene m = MessageQuene.Create(path);// 不知道,反正没有通过

bool b = m.Transactional; // 好像在远端时不支持这个属性了

以上信息在本地时没有任何问题,O(∩_∩)O~

一点补充:

以下只在本地有效,不知道远端是否有效,没试过

如何得到本地的私有队列中的消息的数量(主要代码如下:)

using System.Diagnostics;

return (long)(new PerformanceCounter("MSMQ Queue", "Messages in Queue", path).NextValue());

如果在执行以上代码时出现注册表缺少什么等等的 InvalidOperationException 时,请以管理员的方式在 DOS 中执行

命令 "lodctr /R",也可以通过命令 "perfmon" 查看性能计数器的情况

另外说明在 path 中本地机器名要给全例如 @"MyPC\Private$\MyPath",不能用省略符号 @".\Private$\MyPath"替代

在进行MSMQ的编程时,请添加引用 System.Message.dll 并添加对应的命名空间的引用

其实除了 MSMQ ,我们还是有很多其他的选择的,例如 ActiveMQ 等等,有兴趣大家可以看看了......

关于在集群中使用队列

1、要在集群中使用队列,请在集群中的每个主机的私有队列中创建自己的队列(最好创建事务性队列),例如我的集群中包含两台主机 192.168.117.47、192.168.117.48,共同的漂移地址是192.168.117.50,那我就在每台主机的 MSMQ 的私有队列中分别创建 \private$\MyPath (创建时指定带有事务)

2、在创建队列之后,请在队列的属性中指定用户及该用户对队列的访问权限,否则访问队列的客户端程序将不能正确的发送和接收队列。

3、发送消息时,要使用漂移地址 192.168.117.50 发送,同时指定发送消息时要启用事务

4、接收消息时,请使用单机的 IP 192.168.117.47 或 192.168.117.48 接收队列,同时,请不要指定接收消息的队列启用事务,嘿嘿,这里是不是和不在集群时的情况有些不同,同时也和发送消息有些不一样呢?!

5、之前给出的代码是采用的格式化是 XmlMessageFormatter,这就要求在接收消息时必须要知道消息中对象的类型,如果我们在发送和接收消息时指定 MessageQueue.Formatter = new BinaryMessageFormatter(),则可以在发送和接收消息时不用知道消息中包含的对象的类型了

之前的接收都是同步接收消息,有没有办法来异步获取消息呢?当然可以,代码如下:

主调方代码:

MessageQueue mq = GetMessageQueue(path); // GetMessageQueue 函数如何实现就不写了吧?!

mq.ReceiveCompleted += new ReceiveCompletedEventHandler(mq_ReceiveCompleted);

mq.BeginReceive();

回调函数

private void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)

{

MessageQueue mq = sender as MessageQueue;

if (mq != null && e != null)

{

Message message = mq.EndReceive(e.AsyncResult);

if (message != null)

Console.WriteLine(message.Body);

mq.BeginReceive();

}

}

这是接收消息之后就删除的代码,当然也可以做接收消息但不删除的,这里就不再熬诉了

时间: 2024-10-14 00:30:12

关于访问MSMQ远端私有队列的一点经验的相关文章

关于“在本类中访问本类私有静态变量”的一点疑惑解析

关于"在本类中访问本类私有静态变量"的一点疑惑解析 代码如下: public class StaticVar { private static int x = 100; public static void main(String[] args) { StaticVar var1 = new StaticVar(); var1.x++; StaticVar var2 = new StaticVar(); var2.x++; StaticVar.x++; System.out.print

MSMQ创建消息队列出现“工作组安装计算机不支持该操作”

[sceislqzw]:你在创建公有队列,而你的机器不属于任何域.一般工作组安装的计算机只能创建私有队列. System.Messaging.MessageQueue QueueReceive = new System.Messaging.MessageQueue(@".\Private$\MSMQDemo");这样应该不会出错. [erdgzw]:创建专用队列当然可以.难到创建公有队列必须要在域上啊? [flyaqiao]:if (MessageQueue.Exists(path))

访问类的私有属性(RTTI和模仿类2种方法)

如何访问类的私有属性? 下面以 TPathData 为例,它有一个私有属性 PathData,储存了每一个曲线点,但一般无法修改它,需要利用下面方法,才能访问修改(若有更好的方法,歡迎分享): 一.利用 RTTI 取得类私有属性(建议使用此方法): type TPathDataHelper = class helper for TPathData public function PathData: TList<TPathPoint>; end; function TPathDataHelper

[示例]访问类的私有属性

如何访问类的私有属性? 下面以 TPathData 为例,它有一个私有属性 PathData,储存了每一个曲线点,但一般无法修改它,需要利用下面方法,才能访问修改(若有更好的方法,歡迎分享): 一.利用 RTTI 取得类私有属性(建议使用此方法): type TPathDataHelper = class helper for TPathData public function PathData: TList<TPathPoint>; end; function TPathDataHelper

多线程访问共同资源(队列,多线程,锁机制)

模拟场景:main方法为网络请求线程(也叫生产者线程),在网络请求线程中开启四个线程(消费者线程),进行高效处理队列中的共同资源(生产者线程生产的共同资源),等待资源处理完毕,网络请求线程执行结束,响应客户端. 消费者线程的线程体 1 import java.text.SimpleDateFormat; 2 import java.util.Date; 3 import java.util.concurrent.BlockingQueue; 4 import java.util.concurre

Java利用反射访问对象的私有成员

当我们使用反射为java对象的全部字段逐一赋值的时候,私有字段是不允许直接访问的. 在java.lang.reflect当中,有几个比较实用的API可以解决: getDeclaredFields() :获得所有访问级别的字段 setAccessible(boolean flag): 修改类成员的可访问性 下面以一个JavaBean 对象 转 DBObject 对象的方法为例: public static DBObject bean2DbObject(DBObject dbObject, PicI

C#箴言之用属性来访问类的私有成员

在程序中,难免要访问某个对象的私有成员.那么以前实现这类功能的方法有两种,第一种方法最简单,就是把成员访问符从“private”改为“public”即可:而另一个就是提供公有的成员访问函数来进行访问.那么现在用C#编写程序,就不再需要采用前面所说的两种方法了,而直接使用属性来完成. 首先来看看三种方法的如何实现以及调用的,这里用一个例子来说明,即访问“EmployeeInfo”类的私有成员strName,具体如下表格所示. 那么这三种方法有什么区别呢,用如下的表格,可以更好的说明三者的区别. 因

通过反射访问父类的私有成员

Java语言中,子类是不能访问父类的私有成员的,包括成员变量和方法,但可以通过Java的反射机制去访问. 其实在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象.所以所谓的继承使子类拥有父类所有的属性和方法其实可以这样理解,子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用.就像有些东西你可能拥有,但是你并不能使用.所以子类对象是绝对大于父类对象的,所谓的子类

【c#】队列(Queue)和MSMQ(消息队列)的基础使用

原文:[c#]队列(Queue)和MSMQ(消息队列)的基础使用 首先我们知道队列是先进先出的机制,所以在处理并发是个不错的选择.然后就写两个队列的简单应用. Queue 命名空间 命名空间:System.Collections,不在这里做过多的理论解释,这个东西非常的好理解. 可以看下官方文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.queue?view=netframework-4.7.2 示例代码 我这里