2013-10-10 1 views
1

Я новичок в концепции словарей. Я нашел способ создать простой сервер, способный обрабатывать несколько клиентов. Есть ли способ, которым я мог бы использовать словарь/ConcurrentDictionary для хранения информации, такой как время установления соединения и порт, который он использует для разных клиентов. Я создал отдельный образец словаря, но я не знаю, как заставить его работать с серверным приложением или если он даже будет работать. (Сервер создается с использованием localhost и порта 9090. Клиенты также запускаются локально). Сообщите мне, если вам нужно какое-либо разъяснение. How/Where я бы разместил блок словарного кода, чтобы он мог хранить установленную информацию о подключении или есть другой способ?Как использовать словарь с многопоточным сервером

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); 
     } 
    } 
} 
+0

Я не вижу слова «замок». Нет, похоже, работает, но это не так. –

+0

Что Ганс пытается сказать, так это то, что в вашем коде есть потенциальные проблемы с потоками. Я объяснил более подробно в своем ответе. – bmm6o

ответ

3

Поскольку несколько потоков могут получить доступ к словаря в то же время, вам необходимо либо вручную сериализации доступа к нему (с lock заявления) или пользователь A ConcurrentDictionary. Последний даст лучшую производительность, в общем. Вы можете объявить словарь членом вашего Program и вставить в него из функции AcceptCallback.

Ваш список _clientSockets также разделяется между потоками, поэтому ему также требуется некоторая синхронизация. Возможно, вы сможете полностью избавиться от него, как только ваш словарь будет работать.

 Смежные вопросы

  • Нет связанных вопросов^_^