如何实现良好的消息队列

时间:2015-01-18 14:34:41

标签: c# performance tcpclient

我需要帮助找到消息队列的最佳和最快的数据结构。

架构如下:客户端从外部C ++服务器获取消息(不能查找它的代码)。消息的格式为msg.length + data。

在旧代码中,使用TcpClient类进行连接,将MemoryStream用作队列。客户端从此TCPClient读取数据并将其复制到流中。如果在这个读取客户端读取整个消息,它正在另一个线程中处理,一切都很完美。如果有部分消息或2条消息在一起,代码就会变得非常混乱。

我强烈感觉有可能轻松编写代码。让我烦恼的是" play"在MemoryStream中使用指针,并且需要以某种方式从中删除旧数据。

1 个答案:

答案 0 :(得分:4)

您可以使用Queue类;它就像一个FIFO,先进先出。您需要两个线程(至少)一个来读取来自套接字的消息并入队到FIFO,另一个线程将消息出列并处理它们。您还需要使用互斥锁以防止同时访问队列。这是代码:

    class MessagePacket
    {
        private byte[] data;
        private int length;

        public MessagePacket(int len, byte[] aData)
        {
            this.length = len;
            data = new byte[len];
            Array.Copy(aData, data, len);
        }
        public int Length()
        {
            return this.length;
        }
        public byte[] Data()
        {
            return this.data;
        }
    }

    static Queue<MessagePacket> MsgQueue = new Queue<MessagePacket>();
    static Mutex mutQueue = new Mutex();

    /// <summary> 
    ///     This thread read the message from the sever and put them in the queue.
    /// </summary>
    static void readSocket()
    {
        byte[] dataSize = new byte[4];
        while (true/*or ApplicationIsActive*/)
        {
            try
            {
                // it's assumed that data is a 32bit integer in network byte order
                if (ClientSocket.Receive(dataSize, 4, SocketFlags.None) != 4)
                {
                    return;
                }
                int size = BitConverter.ToInt32(dataSize, 0);
                size = IPAddress.NetworkToHostOrder(size);

                byte[] buffer = new byte[size];
                int offset = 0;
                while (size > 0)
                {
                    int ret = ClientSocket.Receive(buffer, offset, size, SocketFlags.None);
                    if (ret <= 0)
                    {
                        // Socket has been closed or there is an error, quit
                        return;
                    }
                    size -= ret;
                    offset += ret;
                }
                mutQueue.WaitOne();
                try { MsgQueue.Enqueue(new MessagePacket(size, buffer)); }
                finally { mutQueue.ReleaseMutex(); }
            }
            catch  
            {
                return;
            }
        }
    }

    /// <summary> 
    ///     This thread processes the messages in the queue.
    /// </summary>
    static void processMessages()
    {
        while (true/*or ApplicationIsActive*/)
        {
            if (MsgQueue.Count > 0)
            {
                MessagePacket msg;
                mutQueue.WaitOne();
                try { msg = MsgQueue.Dequeue(); }
                finally { mutQueue.ReleaseMutex(); }
                // Process the message: msg
            }
            else Thread.Sleep(50);
        }
    }