Как один поток сервера может обрабатывать несколько клиентов - C#

Узнай цену своей работы

Формулировка задачи:

Есть клиент-серверное приложение, на данный момент 4х потоковое. Моя роль в нем это написание хорошего сервера. Сейчас сервер работает как: 1)Ждёт подключения. 2)Ждёт пока клиент отправит данные. 3)Получает данные. 4)Отправляет ответ и ждёт пока ответ будет получен. 5)Переходит в ожидание следующего подключения клиента (те на пункт 1). Те всё работает в синхронном режиме. В виде кода выглядит так (есть мой класс оболочка для обработки записи и чтения):
Листинг программы
  1. private static void ServerThread(object data)
  2. {
  3. NamedPipeServerStream pipeServer =
  4. new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
  5. //пара логин-пароль для получения инфо от клиента
  6. Tuple<string, string> logpass;
  7. while (true)
  8. {
  9. pipeServer.WaitForConnection();
  10. try
  11. {
  12. StreamRW srw = new StreamRW(pipeServer);
  13. logpass = srw.ReadData();
  14. srw.WriteInt(1);
  15. }
  16. catch (IOException e)
  17. {
  18. Console.WriteLine("ERROR: {0}", e.Message);
  19. }
  20. pipeServer.Disconnect();
  21. }
  22. pipeServer.Close();
  23. }
Как работает мой класс-обёртка для чтения и записи:
Листинг программы
  1. /класс для работы с потоком
  2. //Позволяет писать пары логин-пароль и считывать результаты их обработки
  3. class StreamRW
  4. {
  5. private Stream ioStream;//поток куда писать данные
  6. public StreamRW(Stream stream)
  7. { ioStream = stream; }
  8. //запись пары логин-пароль в поток
  9. public void WriteData(Tuple<string, string> data)
  10. {
  11. byte[] outBuffer;
  12. using (MemoryStream m = new MemoryStream())
  13. using (BinaryWriter writer = new BinaryWriter(m))
  14. {
  15. writer.Write(data.Item1);
  16. writer.Write(data.Item2);
  17. outBuffer = m.ToArray();
  18. }
  19. int len = outBuffer.Length;
  20. ioStream.WriteByte((byte)(len / 256));
  21. ioStream.WriteByte((byte)(len & 255));
  22. ioStream.Write(outBuffer, 0, len);
  23. ioStream.Flush();
  24. }
  25. //чтение пары логин-пароль из потока
  26. public Tuple<string, string> ReadData()
  27. {
  28. Tuple<string, string> result;
  29. int len;
  30. len = ioStream.ReadByte() * 256;
  31. len += ioStream.ReadByte();
  32. byte[] inBuffer = new byte[len];
  33. ioStream.Read(inBuffer, 0, len);
  34. using (MemoryStream m = new MemoryStream(inBuffer))
  35. using (BinaryReader reader = new BinaryReader(m))
  36. {
  37. try
  38. {
  39. result = new Tuple<String, String>(reader.ReadString(), reader.ReadString());
  40. }
  41. catch (IOException ex)
  42. {
  43. Console.WriteLine("Error has occured :(\n" +
  44. "If you'd like to know more, you can google it:" + ex.Message);
  45. result = new Tuple<String, String>("Error", "Error");
  46. }
  47. }
  48. return result;
  49. }
  50. //запись кода результата обработки
  51. public void WriteInt(int answer)
  52. {
  53. byte[] outBuffer = new byte[1] { Convert.ToByte(answer) };
  54. ioStream.Write(outBuffer, 0, 1);
  55. ioStream.Flush();
  56. }
  57. //чтение кода результата обработки (если соединение разорвано на стороне сервера то вернёт -1).
  58. //Исключение выброшено не будет даже если поток закрыт!
  59. public int ReadInt()
  60. {
  61. return Convert.ToInt32(ioStream.ReadByte());
  62. }
  63. }
Преподавателю это не нравиться, мол фигня это всё что сервер в потоке ждет пока клиент ему что-то пришлет и надо мол чтобы это всё асинхронно работало и чтобы поток обрабатывал другого клиента пока этот не хочет отправлять данные например (ну вот для случая что клиент подключился и висит 30 секунд, а потом уже только данные начинает слать). Вот только саму идею асинхронности я не могу понять. Сейчас я пишу и читаю байтики в/из потока через синхронные функции Read и Write. Я вижу что есть также асинхронные Read и Write, но

я не могу понять саму идею: как один поток сервера может обрабатывать несколько клиентов? Те как это он может пока один клиент висит получить данные от другого и ответить ему?

Объясните пожалуйста, с кодом было бы вообще идеально, но хотя бы на словах.

Решение задачи: «Как один поток сервера может обрабатывать несколько клиентов»

textual
Листинг программы
  1. namespace Server
  2. {
  3.     public class PipeServer
  4.     {
  5.         //количество потоков, пока что рассмотрим ситуацию когда = 1
  6.         private int numThreads;
  7.  
  8.         //класс который хранит указатель на открытый канал и байты считанные с него
  9.         private class ConnectionInfo
  10.         {
  11.             public NamedPipeServerStream pipeServer;
  12.             public byte[] buffer;
  13.         }
  14.  
  15.         public PipeServer(int numThreads)
  16.         {
  17.             this.numThreads = numThreads;
  18.         }
  19.  
  20.         //запуск треда на выполнение
  21.         public void Start()
  22.         {
  23.             //создаём экземпляр
  24.             NamedPipeServerStream pipeServer =
  25.                 new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads,
  26.                     PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
  27.  
  28.             //асинхроонное ожидание подключения, при подключении будет вызвано AcceptCallback
  29.             pipeServer.BeginWaitForConnection(new AsyncCallback(AcceptCallback), pipeServer);
  30.  
  31.             Console.WriteLine("\n*** Named pipe server stream started ***\n");
  32.             Console.WriteLine("Waiting for client connect...\n");
  33.         }
  34.  
  35.         //вызывается при подключении к серверу клиента
  36.         /// <param name="result">указатель на открытый канал сервера</param>
  37.         private void AcceptCallback(IAsyncResult result)
  38.         {
  39.             ConnectionInfo connection = new ConnectionInfo();
  40.             connection.pipeServer = (NamedPipeServerStream)result.AsyncState;
  41.  
  42.             //объявляем об окончании ожидания (вроде так нужно тут сделать же?)
  43.             connection.pipeServer.EndWaitForConnection(result);
  44.  
  45.             connection.buffer = new byte[1];//выделим место под информацию для получения от клиента
  46.  
  47.             //когда клиент подключился выведем уведомление об этом
  48.             Console.WriteLine("{0} connected on thread[{1}].",
  49.                 connection.pipeServer.GetImpersonationUserName(), Thread.CurrentThread.ManagedThreadId);
  50.  
  51.             //начать АСИНХРОННОЕ чтение с потока
  52.             connection.pipeServer.BeginRead(connection.buffer, 0, connection.buffer.Length,
  53.                 new AsyncCallback(ReceiveCallback), connection);
  54.                
  55.              //НАЧАТЬ АСИНХРОННОЕ ожидание след. подключеня не даёт - вываливается исключение что
  56.              //канал уже находится в подключ. состоянии
  57.             //connection.pipeServer.BeginWaitForConnection(new AsyncCallback(AcceptCallback), connection.pipeServer);
  58.         }
  59.  
  60.         //вызывается при чтении данных с потока после подключения
  61.         private void ReceiveCallback(IAsyncResult result)
  62.         {
  63.             ConnectionInfo connection = (ConnectionInfo)result.AsyncState;
  64.  
  65.             //считать данные
  66.             StreamRW stream = new StreamRW(connection.pipeServer);
  67.             Tuple<string, string> tuple = stream.ReadTuple(connection.buffer[0]);
  68.  
  69.             Console.WriteLine(tuple.Item1+" "+tuple.Item2);
  70.  
  71.             //записать АСИНХРОННО ответ
  72.             connection.buffer = new byte[1] { 1 };
  73.             connection.pipeServer.BeginWrite(connection.buffer, 0,
  74.                 connection.buffer.Length, SendCallback, connection);
  75.         }
  76.  
  77.         //отправка ответа клиенту. пишеться АСИНХРОННО
  78.         private void SendCallback(IAsyncResult result)
  79.         {
  80.             ConnectionInfo connection = (ConnectionInfo)result.AsyncState;
  81.  
  82.             connection.pipeServer.EndWrite(result);
  83.  
  84.             connection.pipeServer.Disconnect();
  85.             connection.pipeServer.BeginWaitForConnection(new AsyncCallback(AcceptCallback),
  86.             connection.pipeServer);
  87.         }
  88.  
  89.     }
  90.  
  91.  
  92.     class Test
  93.     {
  94.         static void Main(string[] args)
  95.         {
  96.             PipeServer pipe = new PipeServer(1);
  97.             pipe.Start();
  98.             Console.ReadLine();
  99.         }
  100.     }
  101. }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

10   голосов , оценка 4.3 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы