如何使用多线程服务器的字典

时间:2013-10-10 21:59:55

标签: c# multithreading dictionary concurrentdictionary

我是词典概念的新手。我找到了一种方法来创建一个能够处理多个客户端的简单服务器。有没有办法可以使用字典/ ConcurrentDictionary来保存信息,例如建立连接的时间以及它为各种客户端使用的端口。我创建了一个单独的示例字典,但我不知道如何使它与服务器应用程序一起工作,或者它是否可以工作。 (服务器使用localhost和端口9090创建。客户端也在本地运行)。 如果您需要任何澄清,请告诉我。 如何/在哪里放置字典代码块以允许它保存已建立的连接信息,或者是否有不同的/更好的方法来执行此操作?

Dictionary<int, DateTime> ServerDictionary = new Dictionary<int, DateTime>();

        ServerDictionary.Add(9090, DateTime.Now.AddMinutes(5));
            Console.WriteLine("Time List");

            foreach (KeyValuePair<int, DateTime> time in ServerDictionary)
            {
                Console.WriteLine("Port = {0}, Time in 5 = {1}",
                    time.Key, time.Value);
            }
        Console.ReadKey();

以下是服务器代码:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Multi_Server
{
    class Program
    {
        private static Socket _serverSocket;
        private static readonly List<Socket> _clientSockets = new List<Socket>();
        private const int _BUFFER_SIZE = 2048;
        private const int _PORT = 9090;
        private static readonly byte[] _buffer = new byte[_BUFFER_SIZE];

        static void Main()
        {
            Console.Title = "Server";
            SetupServer();
            Console.ReadLine(); // When we press enter close everything
            CloseAllSockets();
        }

        private static void SetupServer()
        {
            Console.WriteLine("Setting up server...");
            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.Bind(new IPEndPoint(IPAddress.Any, _PORT));
            _serverSocket.Listen(5);
            _serverSocket.BeginAccept(AcceptCallback, null);
            Console.WriteLine("Server setup complete");
        }

        // Close all connected client 
        // (we do not need to shutdown the server socket 
        // as its connections are already closed with the clients)
        private static void CloseAllSockets()
        {
            foreach (Socket socket in _clientSockets)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }

            _serverSocket.Close();
        }

        private static void AcceptCallback(IAsyncResult AR)
        {
            Socket socket;

            try
            {
                socket = _serverSocket.EndAccept(AR);
            }
            catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
            {
                return;
            }

            _clientSockets.Add(socket);
            socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
            Console.WriteLine("Client connected, waiting for request...");
            _serverSocket.BeginAccept(AcceptCallback, null);
        }

        private static void ReceiveCallback(IAsyncResult AR)
        {
            Socket current = (Socket)AR.AsyncState;
            int received;

            try
            {
                received = current.EndReceive(AR);
            }
            catch (SocketException)
            {
                Console.WriteLine("Client forcefully disconnected");
                current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
                _clientSockets.Remove(current);
                return;
            }

            byte[] recBuf = new byte[received];
            Array.Copy(_buffer, recBuf, received);
            string text = Encoding.ASCII.GetString(recBuf);
            Console.WriteLine("Received Text: " + text);

            if (text.ToLower() == "get time") // Client requested time
            {
                Console.WriteLine("Text is a 'get time' request");
                byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
                current.Send(data);
                Console.WriteLine("Time sent to client");
            }
            else if (text.ToLower() == "exit") // Client wants to exit gracefully
            {
                // Always Shutdown before closing
                current.Shutdown(SocketShutdown.Both);
                current.Close();
                _clientSockets.Remove(current);
                Console.WriteLine("Client disconnected");
                return;
            }
            else
            {
                //Console.WriteLine("Text is an invalid request");
                byte[] data = Encoding.ASCII.GetBytes("Invalid function request");
                current.Send(data);
                //Console.WriteLine("Warning Sent");
            }

            current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
        }
    }
}

1 个答案:

答案 0 :(得分:3)

由于多个线程可以同时访问您的字典,您需要手动序列化对它的访问(使用lock语句)或用户使用ConcurrentDictionary。一般而言,后者将提供更好的性能。您可以将字典声明为Program类的成员,并从AcceptCallback函数插入其中。

您的_clientSockets列表也在线程之间共享,因此它也需要一些同步。一旦你的字典工作,也许你可以完全摆脱它。