这里应该将私有队列称做“专用队列”好像更贴切一些了,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();
            }
}
这是接收消息之后就删除的代码,当然也可以做接收消息但不删除的,这里就不再熬诉了

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

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

    [sceislqzw]:你在创建公有队列,而你的机器不属于任何域.一般工作组安装的计算机只能创建私有队列. System.Messaging.MessageQueue QueueReceive = n ...

  2. VC6.0中重载操作符函数无法访问类的私有成员

    整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...

  3. 七牛云音频转码准备工作之如何创建音视频处理私有队列pipeline

    如何创建音视频处理私有队列 最近更新时间:2017-08-28 15:54:45 在七牛进行音视频处理,推荐使用私有队列(pipeline). 创建私有队列方法如下: 第一步 登录七牛开发者平台 ht ...

  4. c++中嵌套类,外部类访问内部类的私有成员变量

    在嵌套类中,内部类可以直接访问外部类的私有成员变量,但是外部类不能直接访问内部类的私有成员变量,必须把外部类声明为内部类的友元类 /********************************** ...

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

    在程序中,难免要访问某个对象的私有成员.那么以前实现这类功能的方法有两种,第一种方法最简单,就是把成员访问符从“private”改为“public”即可:而另一个就是提供公有的成员访问函数来进行访问. ...

  6. java利用反射访问类的私有(private)属性及方法

    Java语言中,在一个类中,为了不让外界访问到有的属性和方法,通常将其设置为private,用正常的方式(对象名.属性名,对象名.方法名)将无法访问此属性与方法,但有没有其他方法可以访问呢?答案是有的 ...

  7. C++笔记之外部类访问内部类的私有成员

    如下图所示 内部类可以访问外部类的私有成员 而外部类无法访问内部类的私有成员 为了能让外部类访问内部类的私有成员,将外部类声明为内部类的友元类即可 #include <iostream> ...

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

    如何访问类的私有属性? 下面以 TPathData 为例,它有一个私有属性 PathData,储存了每一个曲线点,但一般无法修改它,需要利用下面方法,才能访问修改(若有更好的方法,歡迎分享): 一.利 ...

  9. Delphi 跨单元进入(访问)类的私有成员,protected ,private部分

    http://blog.sina.com.cn/s/blog_5f8861b60102v1nl.html Delphi 跨单元进入(访问)类的私有成员,protected ,private部分 (20 ...

随机推荐

  1. LinearLayout具体解释一:LinearLayout的简单介绍

    LinearLayout,中文意思是线性布局.假设你是初学android的,肯定会非常困惑"啥叫布局",啥又叫"线性布局"呢. 有的时候,我尝试用官方的语言去解 ...

  2. Mybatis深入之事务管理

    Mybatis之事务管理 简单介绍 Mybatis的事务管理分为两种JdbcTransaction.ManagedTransaction. 当中JdbcTransaction仅仅是对数据库连接Conn ...

  3. 《Qt on Android核心编程》夹

    china-pub在售前,售中环节退房,折扣低! 有朋友想看看<Qt on Android核心编程>的文件夹,So-- 文件夹     <Qt on Android核心编程>文 ...

  4. Unity3D方法来隐藏和显示对象

    Unity3D作 在使用unity3d开发游戏的过程中.我们经常会遇到须要隐藏或者显示的操作,针对这一点,以下做了一些总结. 一.设置Renderer状态 在游戏的开发中,全部可以被渲染的物体都包括有 ...

  5. 构建安全的Xml Web Service系列之SSL篇

    原文:构建安全的Xml Web Service系列之SSL篇 首先介绍一下SSL, SSL 的英文全称是 "Secure Sockets Layer" ,中文名为 "安全 ...

  6. python基础课程_学习笔记26:编程的乐趣

    编程的乐趣 编程柔术 当你坐下来,打算如何组织计划要定时,具体程序,然而,无论什么经验.在实现时间的函数的,你会逐渐学会了原来的设计,实用的新知识.我们不应该忽视沿途汲取的教训,相反,它们用于其他设计 ...

  7. 开发随笔——NOT IN vs NOT EXISTS

    原文:开发随笔--NOT IN vs NOT EXISTS 原文出处: http://blog.csdn.net/dba_huangzj/article/details/31374037  转载请引用 ...

  8. JAVA基础实例(三)--排序

    冒泡排序 是一种简单的排序算法.它反复地走訪过要排序的数列,一次比較两个元素.假设他们的顺序错误就把他们交换过来.走訪数列的工作是反复地进行直到没有再须要交换,也就是说该数列已经排序完毕. 这个算法的 ...

  9. DOM简要

    在看Js视频的时候就感觉Dom这东西太奇妙了.在这个注重用户体验的Web设计时代里.Dom是至关重要的. 它的易用性强.而且遍历简单.支持XPath. 它既然这么强大那么就来简单的介绍Dom这个东东. ...

  10. Windows 事件查看器(收集)

    原文:Windows 事件查看器(收集) 事件查看器相当于一本厚厚的系统日志,可以查看关于硬件.软件和系统问题的信息,也可以监视 Windows 的安全事件 提示:除了可以在"控制面板→管理 ...