65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MSMQ 聊天

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.91/5 (14投票s)

2008年11月17日

CPOL

5分钟阅读

viewsIcon

47565

downloadIcon

1624

使用 MSMQ 实现两台机器之间的通信。

引言

这是一个用于局域网(LAN)中使用的聊天应用程序,它使用了 MSMQ。在该应用程序中,我们将设置一个服务器来维护所有消息,客户端机器可以发送或接收消息。

安装

在使用此应用程序之前,我们应该在服务器和客户端机器上安装 MSMQ。MSMQ 是 Microsoft Windows 提供的一种功能。在安装操作系统时,默认情况下它不会被安装;您需要从“控制面板”->“添加/删除程序”->“添加/删除 Windows 组件”->“消息队列”中手动安装它。

什么是 MSMQ?

MSMQ 是 Microsoft 的消息队列,它允许两台计算机之间进行通信。您可以发送和接收消息,而无需担心它们是否已送达另一台机器。MSMQ 允许将消息放入队列,如果用户当前不在线,消息将保留在队列中。一旦用户接收到消息,它就会被删除。在许多应用程序中,需要将数据或消息发送到另一个系统,这可以通过多种方式实现。但请考虑这样一种情况:您想发送一条消息,而不关心对方系统当前是否可用。您只想发送它,当用户在其系统上启动应用程序时,他应该能收到那条消息。需要在两个应用程序之间存在一个东西来管理通信并处理这些问题。一种可以克服这些问题的软件称为消息队列系统。与 IIS 4.0 配合使用的消息队列系统称为 Microsoft Message Queue System (MSMQ)。

为什么以及何时我们需要这样的功能:设想这样一种情况,我们需要通过多个客户服务代表来处理客户请求。我们将使用一个 Web 应用程序从客户端获取请求,然后将其存储在数据库中。现在,我们需要检索这些请求并将它们分发给多个代表。一个限制是这些请求不能从外部机器处理。只有当机器在域内时,它才应该能够安装应用程序并处理请求。现在,为了实现这个功能,有很多种方法。但是我们可以使用 MSMQ 来实现相同的功能。在本篇文章中,我不会实现全部功能,而只是实现其中的一部分。也就是说,我们将实现消息传递器的功能,我们可以将消息放入队列,接收者可以在他上线时随时接收到它。下面是图和代码…

一个想法!!!

ChatDiagram.jpg

在上图所示的流程中,我们可以看到我们将为多个用户创建消息队列以接收队列中的消息。如果 C 和 B 想发送消息给 A,那么他们会将消息放入属于 A 的队列,即“QueueA”。反之亦然。创建独立队列的一个优点是,所有用户都可以将他们的消息放入该队列,接收者可以在他上线时随时接收到该消息。

Chat.jpg

向队列写入消息

整个代码和注释都是自 explanatory 的。第一步是检查是否存在消息队列,通过使用当前系统名称来判断。如果不存在,我们就创建它。要创建消息队列,我们使用以下代码:

if (!MessageQueue.Exists(@"ServerName\QueueName"))
{
    MessageQueue.Create(@"ServerName\QueueName", false);
    MessageBox.Show("Queue named queuemsgs is created on your m/c");
}

使用上述代码,我们可以使用机器名称创建消息队列。首先,我们需要检查队列是否已存在。

这是发送消息到消息队列的代码。但在发送消息之前,您需要创建消息队列。还有一点是,您需要决定一个服务器来维护所有队列,并且必须将该系统名称提供为“ServerName”。

static string selectedmcname = "ServerName";
private void BtnSend_Click(object sender, EventArgs e)
{
    //The code for Sending message.
    try
    {
        MessageQueue msgQ_Send = new MessageQueue();

        if (ConB_SendTo.Text != "")
        {
            //Select User to which you want to send message.
            msgQ_Send.Path = @"FormatName:DIRECT=OS:" + ConB_SendTo.Text;
        } 
        else
        {
            //General queue for sending messages
            msgQ_Send.Path = @"FormatName:DIRECT=OS:" + Generalqueue;
        } 

        //Send all information that u want, along with the message
        RequestInformation objMsg = new RequestInformation();
        objMsg.Name = TxtYourName.Text;
        objMsg.Message = TxtSend.Text;

        //Bind your message with Message Class.
        System.Messaging.Message m = new System.Messaging.Message();
        m.Body = objMsg;
        m.Formatter = new BinaryMessageFormatter();
        m.AppSpecific = 34;

        //sending message along with other information. 
        //Second parameter we are passing is called 'LABEL'
        //By which we can send some more information 
        //so that one can use it farther for the implimentation
        //of functionality such as filteration of messages.
        msgQ_Send.Send(m, DateTime.Now.ToLongTimeString() + 
             "::" + System.Environment.MachineName);

        //see what message you sent.
        TxtMsg.Text += "\r\n" + Environment.MachineName + ": " + TxtSend.Text;

        TxtSend.Text = "";
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error");
    }
}

上面提到的 `RequestInformation` 类是为了存储您想随消息一起发送的所有信息而定义的。其背后的逻辑是,我们可以序列化该类对象,然后通过二进制序列化来发送它。这样,我们可以一次发送多条消息,或者发送一条消息以及其他信息。下面是类的定义…

using System;
using System.Collections.Generic;
using System.Text;

namespace MessageQueueDemo
{
    //Attribute must be added for mesioning class can be serialize
    [Serializable]
    public class RequestInformation
    {
        public RequestInformation()
        {
        }
        //one can add number of variables or inforation in this class 
        //like address, MobileNumber.
        public string Name;
    
        public string Message;
    }
}

该类应标记为可序列化。在定义类时,我们也可以使用私有变量,以及一些公共方法来存储信息。

从队列读取

这是一个页面加载事件。在这里,我们需要启动一个线程,该线程将不断地检查队列中是否有新消息。

private void ChatWindow_Load(object sender, EventArgs e)
{
    try
    {
        //List all Message Queue's available.
        MessageQueue[] queues = MessageQueue.GetPublicQueues();
        //Fill combo box with all queues.
        foreach (MessageQueue queue in MessageQueue.GetPublicQueues())
        {
            ConB_SendTo.Items.Add(queue.Path);
        }
    }

    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    //Start Thread which will keep track on incoming messages.
    Thread th = new Thread(GetMesqueue);
    th.Start();
}

这是具有从队列接收消息功能的方​​法

private void GetMesqueue()
{
    //To avoid cross threading
    CheckForIllegalCrossThreadCalls = false;
    while (true)
    {
        try
        {
            //If message queue is not in the list then create it on server.
            if (!MessageQueue.Exists(ServerName + @"\" + Environment.MachineName))
            {
                MessageQueue.Create(ServerName + @"\" + Environment.MachineName);
            }
            //User can get messages from queue which belongs to his machine name.
            MessageQueue msgqueue_Get = new MessageQueue();
            msgqueue_Get.Path = @"FormatName:DIRECT=OS:" + 
                     ServerName + @"\" + Environment.MachineName;
            Type[] target = new Type[1];
            target[0] = typeof(string);

            //Time out is 2 seconds.
            System.Messaging.Message msg = msgqueue_Get.Receive(new TimeSpan(0, 0, 2));
            //Formatter for deserialization of message 
            msg.Formatter = new System.Messaging.BinaryMessageFormatter();

            //Deserialization of a message.
            RequestInformation info = (RequestInformation)msg.Body;
          
            TxtMsg.Text += "\r\n" + info.Name+" : "+info.Message;
        }
        catch (Exception ex)
        {
            //Check whether Queue is empty? if empty then go farther
            //if not then give a message bax with 
            //error message.
            if (ex.Message != "Timeout for the requested operation has expired.")
            {
                MessageBox.Show(ex.Message, "Error");
                break;
            }
        }
    }
}

结论

本文档是关于创建一个消息队列以将消息发送给多个用户的。无需创建或维护单独的 XML 文件来发送数据;让 Windows 来处理数据传输和队列维护。我们只需要创建队列并发送消息。我们可以进一步将其实现为通过 HTTP 传输。

备选方案

我们可能熟悉 `FileSystemWatcher` 类的概念。通过使用这个类,我们可以跟踪目录或文件所做的更改。我们可以使用 XML 文件来存储数据或共享数据。该文件可以放在共享文件夹中。这样,我们就可以通过 XML 文件和 `FileSystemWatcher` 来传输消息。最后,我们必须手动完成所有事情,这是一项繁琐的任务。

© . All rights reserved.