win7訪問遠端Windows Server 2008R2消息隊列拒絕

https://blog.csdn.net/jiyiqinlovexx/article/details/17803857

問題:

下面是我的創建消息隊列的代碼,放在服務器端運行:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;
 
namespace MSMQBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            MessageQueue mq = null;
            //顯示創建自身的消息隊列
            const string queueName = @".\Private$\jiyiqin";
            if (!MessageQueue.Exists(queueName))
            {
                mq = System.Messaging.MessageQueue.Create(queueName);
                Console.WriteLine("創建消息隊列完成:" + queueName);
            }
            else
            {
                mq = new System.Messaging.MessageQueue(queueName);
            }
            mq.SetPermissions("Administrator", MessageQueueAccessRights.FullControl);
            mq.SetPermissions("ANONYMOUS LOGON", MessageQueueAccessRights.FullControl);
            mq.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);
        }
    }
}

下面是我的發送消息和去遠端服務器的消息隊列查詢消息的代碼,在win7上面運行:
using System;
using System.Messaging;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using CBIP.CProxy.AsyncMsgSender;
 
namespace ClientNTService1
{
    class Program
    {
        static void Main(string[] args)
        {
            SendMsg();
 
            ReceiveMsg();
        }
 
        static void SendMsg()
        {
            const string queueName = @"FormatName:Direct=TCP:192.168.1.108\Private$\jiyiqin";
            AsyncMessage message = new AsyncMessage
            {
                UserID = 352,
                MessageReceiver = "某某某接受者",
                MessageSender = "CMS Administrator",
                MessageSendIP = "192.168.0.1",
                SendTime = DateTime.Now.ToString(),
                MessageCode = "109001001",
                MessageBody = "CMS測試消息,內容包含超鏈接 http://bbs.jlitrdc.com/bbs/ ,點擊跳轉"
            };
 
            try
            {
                //將異步消息發往指定的消息隊列
                using (MessageQueue msmq = new MessageQueue(queueName))
                {
                    msmq.Formatter = new XmlMessageFormatter(new Type[] { typeof(AsyncMessage) });
                    System.Messaging.Message msg = new Message() { Label = "業務模塊異步消息", Body = message };
                    msmq.Send(msg);
                }
            }
            catch (Exception ee)
            {
                Console.WriteLine(String.Format("消息發送失敗,原因是:{0}", ee.Message));
            }
 
            Console.WriteLine("發送完成,按任意鍵退出...");
            //Console.ReadKey();
            
        }
 
        static void ReceiveMsg()
        {
            const string queueName = @"FormatName:Direct=TCP:192.168.1.108\Private$\jiyiqin";
            //while (true)
            //{
            MessageQueue MQ = new MessageQueue(queueName);
 
            System.Messaging.Message message = null;
            try
            {
                message = MQ.Receive(TimeSpan.FromSeconds(3));
            }
            catch (Exception ee)
            {
                message = null;
                Console.WriteLine("從消息隊列輪訓消息出現異常,原因是:" + ee.Message);
                //continue; 
            }
 
            if (message != null)
            {
                message.Formatter = new XmlMessageFormatter(new Type[] { typeof(AsyncMessage) });
                AsyncMessage msg = (AsyncMessage)message.Body;
                Console.WriteLine("輪訓線程接收到一個異步消息: UserID is " + msg.UserID);
            }
            //}
        }
    }
}

運行之後提示: Access to remote messaging queue is denied。 Windows Server 2003沒有這個問題。


解決方法:

1、消息隊列本身的權限:

右擊你的消息隊列選擇屬性,切換到安全tab頁,看是不是ananymous logon,everyone,administrator都已經是完全控制了,如果不是勾選上。

2、Windows  Server 2008的消息隊列安全訪問控制設置

(1)更改註冊表項:

定位到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSMQ\Parameters\security 下面,新建一個DWIRD項: NewRemoteReadServerAllowNoneSecurityClient,設置值爲1。

原因: http://technet.microsoft.com/zh-cn/library/cc759412(v=ws.10).aspx

(2)啓用入站規則

原因:http://blogs.msdn.com/b/johnbreakwell/archive/2008/07/10/getting-msmq-messages-out-of-windows-server-2008.aspx

(3)修改消息隊列屬性,允許遠端RPC訪問:

右擊消息隊列選擇屬性。

將“禁用未經身份驗證的RPC調用” 前面的勾去掉。

原因:http://blogs.msdn.com/b/johnbreakwell/archive/2008/02/12/msmq-4-0-what-s-new-in-computer-management.aspx

這樣設置好了之後,可以發現防火牆允許的列表中多了消息隊列,註冊表項也多了一項:

然後我馬上在win7上運行我前面貼出來的發送消息和讀取消息的程序,發現消息發送不過去了。。。

然後我把消息發送的程序拷貝到windows server 2008上面運行,消息能夠發進去,然後再回到win7運行發送消息和讀取消息的程序,竟然能夠工作了!!!

不知道是不是需要去發一下消息,激活一下。。。 好蒼白的解釋,不過總算是OK了。

猜想性提示:

如果按照上面做了,還是不行。

我想說的是我的windows server 2008雖然是虛擬機,但是和我的win7是在同一個網段內(與win7是橋接方式連接),工作組都是WORKGROUP,這些都有可能是導致我這裏能夠正常工作的原因。

如果你按照我上面介紹的設置了,還是不能正常工作,可能是因爲兩臺機器不在同一個工作組,或者雖然能相互ping通,但是不在同一個子網等等,我不確定,只是提醒你注意一下可能是這些原因。

你也許可以在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSMQ\Parameters\security 下面加一個註冊表項:NewRemoteReadServerDenyWorkgroupClient,並將其設置爲 1,試一試。

如果你遇到按照我的設置了還是不能工作,但是最後解決了這個問題的,請留言或者郵件([email protected])告訴我,學習一下,謝謝。

====================== 2014-1-4補充:

果然不出我所料,如果win7和server08不在同一個域或者工作組中,上面講的都無法工作。。。 這個問題還不知道怎麼解決。

我的win7是加入到了公司的域中,而我的windows server 2008是加入到的默認的工作組WORKGROUP中,然後我反覆在win7上運行我的上面貼出來的那個發送消息和接收消息的程序,下面兩個錯誤交替出現:

錯誤1: Access to remote messaging queue is denied

錯誤2:下面的錯誤描述摘自網絡,我和他一樣:

I've asked this question in the MSDN forum, I got a lot of help there from John Breakwell, but I couldn't solve my issue and now I am running in circles (again). So maybe someone here can help me.

I have a remote private queue, a producer application and a consumer application. I am using Windows Server 2008 with MSMQ.

I can send the message using my producer app, but I can't read it using my consumer. Here is my consumer code

MessageQueue rmQ = new MessageQueue("FormatName:Direct=OS:<hostname>\\private$\\<queuename>");
System.Messaging.Message msg = rmQ.Receive();
I get an exception in the second line, the exception is null without any information, except for the stack trace

System.Messaging.MessageQueueException (0x80004005) at System.Messaging.MessageQueue.MQCacheableInfo.get_ReadHandle() at System.Messaging.MessageQueue.StaleSafeReceiveMessage(UInt32 timeout, Int3 2 action, MQPROPS properties, NativeOverlapped* overlapped, ReceiveCallback rece iveCallback, CursorHandle cursorHandle, IntPtr transaction) at System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32 actio n, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction in ternalTransaction, MessageQueueTransactionType transactionType) at System.Messaging.MessageQueue.Receive() at consumer.Program.Main(String[] args) in C:\Users\usr\Documents\Visua l Studio 2010\Projects\loadQueueTest\consumer\Program.cs:line 20

I've read a lot of things, so I have already done somethings:

I've set the anonymous logon to have full access on the queue
I've set my domain user as the administrator on the server
Opened the ports for MSMQ and RPC
Disabled the Firewall
I also used rpcping and portqry to perform some diagnostics, I am not an expert, but it seems ok.

Does anyone knows what I am missing?

Thanks, Oscar

============================== 下面是我在MSDN找到的一段話,我來翻譯一下:

Reading Messages from Remote Queues
3 out of 5 rated this helpful - Rate this topic
Although remote read operations are not part of the optimal messaging model, reading messages from remote nontransactional queues is fully supported. Remote reading is typically used to distribute the work load among servers. Remote reading is a high-overhead and therefore inefficient process. Including remote read operations in an application limits scaling.

Message Queuing supports sending transactional messages to remote queues, but does not support reading messages from a remote queue within a transaction. This means that reliable, exactly-once reception is not available from remote queues.

Messages can be retrieved from a remote private queue on an MSMQ 3.0 computer when either the local or remote computer is operating in workgroup mode only if the queue's default security descriptor is changed to grant the Receive Message permission to anonymous users.

Message Queuing does not support reading of messages from a remote queue if the remote queue resides in a different AD forest.

儘管遠端的讀操作不是最優的消息模式,但是從遠端的非事務性隊列讀取消息仍然是支持的。
遠端讀取典型地應用於在多個服務器中分發工作負載。遠端讀取開銷非常高,因此效率不高,而且遠端讀取操作會限制應用的可拓展性。(譯者註解:主動到遠端服務器讀取消息可拓展性感覺上沒有被動接收消息的可拓展性高)

消息隊列支持發送事務性消息到遠端隊列,但是不支持從遠端隊列讀取事務性消息,這意味着遠端隊列無法做到可靠的、無重複的消息工作模式。

在支持MSMQ3.0以上的計算機上,支持讀取遠端私有隊列中的消息,但是這個本地的或者遠端的計算機必須工作在“工作組模式”下,並且隊列默認的安全描述符需要被修改來授予匿名用戶接受消息的權限。

(譯者註釋:

1、我們都知道計算機可以工作在工作組模式、或者域模式下,它這裏只提到了必須在工作組模式下,沒有提到兩臺計算機都工作在域模式下,並且在同一個域中,是否還能夠遠端讀取,這個我去試一試再來補充。

2、我今天將我的windows server2008原來的工作組從默認的和win7同一個的工作組WORKGROUP改爲WORKGROUP1,然後就遠程不上了,但是能夠ping通,而且仍然能夠在win7上對其進行遠程消息讀取。。。不知道是不是不論在什麼工作組,只要在工作組模式就可以,或者與我的08服務器(虛擬機)和我的win7的網絡設置是橋接方式有關)

假如兩臺機器在不同的AD(Active Directory)林中,那麼消息隊列不支持遠端消息讀取。

==========================還有一些問題需要進一步確認:

1、同一個AD林(域)中是不是可以遠端訪問私有隊列?(我猜測可以,如果哪天發現不行了,再來修改這個答案)

2、不同AD林中不支持遠端讀取,私有隊列是肯定的,但是公共隊列呢?是否也不支持?(我猜測不可以,還是一樣哪天發現支持,額再來修改這個答案)

3、關於創建公共隊列:

MSDN有句話:可以在自己的計算機上或享有域或者企業管理訪問權限的任何“消息隊列”計算機上創建公共隊列。還可以僅在本地計算機上創建專用隊列。

意思就是隻要加入到了域,就可以創建公共隊列。反過來就是說,如果沒有加入到域,就別想公共隊列的事了。

首先可以確定的是要創建公共隊列必須 將計算機加入到域中(但是加入到哪個域?任何一個域都可以麼?),並且是不是加入到了域,然後安裝消息隊列的時候將“MSMQ Active Directory 域服務集成/目錄服務集成”選項勾選上就可以創建公共隊列了?

我想起來我的公司的電腦是已經加入到公司的域中了,明天上班去看看它上面是不是真的有公共隊列,反正我現在身邊所有電腦都沒有,它們也都沒有加入到任何域中。

============================ 關於windows server 2003上的消息隊列:

我上面所講的全部都是針對Windows Server 2008的。

如果是windows server 2003就完全不一樣了。我已經試過了,就算是win7加入到了特定域,而windows server 2003沒有加入任何域,還是默認的WORKGROUP工作組,也就是說它們兩個不在同一個AD林(域)中,win7仍然能夠遠程讀取windows server 2003上面私有隊列的消息。

我猜想是windows server 2003針對消息隊列沒有引入安全訪問控制機制,這應該是server 2008以後纔有的機制。

============================ 總結:

既然MSDN上都說了,遠端訪問消息隊列效率不高,然後還有這樣那樣限制,我們爲什麼一定要這樣去訪問呢。

目的都是去遠端機器拿消息隊列,可以通過RPC,讓RPC服務在服務器上本地訪問消息隊列,不更好麼!!!

參考:http://blogs.msdn.com/b/johnbreakwell/archive/2010/03/24/understanding-how-msmq-security-blocks-rpc-traffic.aspx
————————————————
版權聲明:本文爲CSDN博主「小弟季義欽」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/jiyiqinlovexx/article/details/17803857

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章