MSMQ和轮询接收消息?

时间:2009-07-29 05:27:49

标签: .net msmq

我有一个Windows 服务可以进行一些图像转换。它可以在重命名任何文件(在特定文件夹中)时触发(即重命名文件观察者)。工作得很好,直到我在该文件夹中转储(和重命名)大量图像。 CPU红线等。

所以,我打算将我的代码更改为使用 MSMQ 排队所有需要转换的文件。精细。每次重命名文件并触发文件监视器时,我都会向队列中添加一条新消息。 KEWL。

问题是这个 - > 如何从队列中一次抓取一条消息?

我是否需要制作一个定时器对象,每隔xxx秒轮询一次队列?或者有没有办法不断窥视队列中的第一个项目。一旦消息存在,提取它,处理它,然后继续(这意味着,继续偷看直到世界爆炸)。

我想知道我是否只需要在Receive方法周围放置一个while循环。 Pseduo代码如下(在编辑#2中)......

任何人都有这方面的经验并有一些建议吗?

非常感谢!

编辑:

如果可以使用WCF,有人可以提供一些示例代码等吗?

编辑2:

这是我想到的一些伪代码......

// Windows service start method.
protected override void OnStart(string[] args)
{
   // some initialisation stuf...

   // Start polling the queue.
   StartPollingMSMQ();

   // ....
}

private static void StartPollingMSMQ()
{
    // NOTE: This code should check if the queue exists, instead of just assuming it does.
    //       Left out for berevity.
    MessageQueue messageQueue = new MessageQueue(".\\Foo");

    while (true)
    {
        // This blocks/hangs here until a message is received.
        Message message = messageQueue.Receive(new TimeSpan(0, 0, 1));

        // Woot! we have something.. now process it...
        DoStuffWithMessage(message);

        // Now repeat for eva and eva and boomski...
    }
}

5 个答案:

答案 0 :(得分:26)

如果使用本地队列,则不需要WCF。

这是我的示例服务(来自Windows服务项目的服务)的看法:

using System.Messaging;
public partial class MQProcessTest1 : ServiceBase
{
    //a name of the queue
    private const string MqName = @".\Private$\test1";
    //define static local private queue
    private static MessageQueue _mq;
    //lazy local property through which we access queue (it initializes queue when needed)
    private static MessageQueue mq
    {
        get
        {
            if (_mq == null)
            {
                if (!MessageQueue.Exists(MqName))
                    MessageQueue.Create(MqName);
                _mq = new MessageQueue(MqName, QueueAccessMode.ReceiveAndAdmin);
                _mq.Formatter = new BinaryMessageFormatter();
            }
            return _mq;
        }
    }

    //constructor
    public MQProcessTest1()
    {
        InitializeComponent();
        //event to process received message 
        mq.ReceiveCompleted += new ReceiveCompletedEventHandler(mq_ReceiveCompleted);
    }

    //method to process message
    private void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
    {
        //queue that have received a message
        MessageQueue cmq = (MessageQueue)sender;
        try
        {
            //a message we have received (it is already removed from queue)
            Message msg = cmq.EndReceive(e.AsyncResult);
            //here you can process a message
        }
        catch
        {
        }
        //refresh queue just in case any changes occurred (optional)
        cmq.Refresh();
        //tell MessageQueue to receive next message when it arrives
        cmq.BeginReceive();
    }

    protected override void OnStart(string[] args)
    {
        //let start receive a message (when arrives)
        if (mq != null)
            mq.BeginReceive();
        //you can do any additional logic if mq == null
    }

    protected override void OnStop()
    {
        //close MessageQueue on service stop
        if (mq != null)
            mq.Close();
        return;
    }
}

答案 1 :(得分:1)

我的印象是MSMQ的构建与IBM的MQ产品兼容。如果 ,则可以使用超时调用MQGET,而不必担心轮询。

只需从队列中获取一条消息(例如)。如果那里有一个,处理它。然后,如果需要,可以退出服务,或者等待返回MQGET。

这意味着您的服务不会不必要地占用CPU时间,但如果发出信号,它仍然可以及时退出。

一般来说,你会有类似的东西:

Set up all queue stuff.
while true:
    Read from queue with 10-second timeout.
    If message was read:
        Process message
    If signaled to exit:
        break
Tear down queue stuff.
Exit.

答案 2 :(得分:1)

在ViktorJ示例中使用事件args来获取您的消息而不是发送者到新的MessageQueue,这肯定会更有效吗?然后使用静态字段mq调用mq.BeginReceive,否则调用内存

答案 3 :(得分:0)

听起来你需要调查WCF。

Queues in Windows Communication Foundation

  

负载均衡。发送申请   可以压倒接收申请   与消息。队列可以管理   不匹配的消息生成和   消费率使接收者   并不是不堪重负。

以下是使用WCF and MSMQ

的示例

答案 4 :(得分:0)

请注意,服务示例将在OnStart()处阻止。而是启动一个工作线程:

    protected override void OnStart(string[] args)
    {
        IntPtr handle = this.ServiceHandle;
        myServiceStatus.currentState = (int)State.SERVICE_START_PENDING;
        SetServiceStatus(handle, ref myServiceStatus);

        // Start a separate thread that does the actual work.

        if ((workerThread == null) ||
            ((workerThread.ThreadState &
             (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
        {
            workerThread = new Thread(new ThreadStart(ServiceWorkerMethod));
            workerThread.Start();
        }

    }

然后从worker调用BeginReceive()。