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


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

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

    下面说说我的经验
    1、首先要保证远端的主机和本地机器同时加入到了同一个域中
    2、要通过管理工具在远端主机中创建私有的队列,例如 192.168.117.47Private$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 中本地机器名要给全例如 @"MyPCPrivate$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();
                }
    }
    这是接收消息之后就删除的代码,当然也可以做接收消息但不删除的,这里就不再熬诉了
  • 相关阅读:
    使用composer命令加载vendor中的第三方类库
    微信小程序
    php无限分类方法类
    php的多功能文件操作类
    计算地图上两点间的距离PHP类
    php的微信公众平台开发接口类
    身份证验证PHP类
    PHP实现微信对账单处理
    PHP实现微信退款功能
    sqlserver 多库查询 sp_addlinkedserver使用方法(添加链接服务器)
  • 原文地址:https://www.cnblogs.com/itjeff/p/6026861.html
Copyright © 2020-2023  润新知