Как один поток сервера может обрабатывать несколько клиентов - C#
Формулировка задачи:
Есть клиент-серверное приложение, на данный момент 4х потоковое. Моя роль в нем это написание хорошего сервера.
Сейчас сервер работает как:
1)Ждёт подключения.
2)Ждёт пока клиент отправит данные.
3)Получает данные.
4)Отправляет ответ и ждёт пока ответ будет получен.
5)Переходит в ожидание следующего подключения клиента (те на пункт 1).
Те всё работает в синхронном режиме.
В виде кода выглядит так (есть мой класс оболочка для обработки записи и чтения):
Как работает мой класс-обёртка для чтения и записи:
Преподавателю это не нравиться, мол фигня это всё что сервер в потоке ждет пока клиент ему что-то пришлет и надо мол чтобы это всё асинхронно работало и чтобы поток обрабатывал другого клиента пока этот не хочет отправлять данные например (ну вот для случая что клиент подключился и висит 30 секунд, а потом уже только данные начинает слать). Вот только саму идею асинхронности я не могу понять. Сейчас я пишу и читаю байтики в/из потока через синхронные функции Read и Write. Я вижу что есть также асинхронные Read и Write, но
Листинг программы
- private static void ServerThread(object data)
- {
- NamedPipeServerStream pipeServer =
- new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
- //пара логин-пароль для получения инфо от клиента
- Tuple<string, string> logpass;
- while (true)
- {
- pipeServer.WaitForConnection();
- try
- {
- StreamRW srw = new StreamRW(pipeServer);
- logpass = srw.ReadData();
- srw.WriteInt(1);
- }
- catch (IOException e)
- {
- Console.WriteLine("ERROR: {0}", e.Message);
- }
- pipeServer.Disconnect();
- }
- pipeServer.Close();
- }
Листинг программы
- /класс для работы с потоком
- //Позволяет писать пары логин-пароль и считывать результаты их обработки
- class StreamRW
- {
- private Stream ioStream;//поток куда писать данные
- public StreamRW(Stream stream)
- { ioStream = stream; }
- //запись пары логин-пароль в поток
- public void WriteData(Tuple<string, string> data)
- {
- byte[] outBuffer;
- using (MemoryStream m = new MemoryStream())
- using (BinaryWriter writer = new BinaryWriter(m))
- {
- writer.Write(data.Item1);
- writer.Write(data.Item2);
- outBuffer = m.ToArray();
- }
- int len = outBuffer.Length;
- ioStream.WriteByte((byte)(len / 256));
- ioStream.WriteByte((byte)(len & 255));
- ioStream.Write(outBuffer, 0, len);
- ioStream.Flush();
- }
- //чтение пары логин-пароль из потока
- public Tuple<string, string> ReadData()
- {
- Tuple<string, string> result;
- int len;
- len = ioStream.ReadByte() * 256;
- len += ioStream.ReadByte();
- byte[] inBuffer = new byte[len];
- ioStream.Read(inBuffer, 0, len);
- using (MemoryStream m = new MemoryStream(inBuffer))
- using (BinaryReader reader = new BinaryReader(m))
- {
- try
- {
- result = new Tuple<String, String>(reader.ReadString(), reader.ReadString());
- }
- catch (IOException ex)
- {
- Console.WriteLine("Error has occured :(\n" +
- "If you'd like to know more, you can google it:" + ex.Message);
- result = new Tuple<String, String>("Error", "Error");
- }
- }
- return result;
- }
- //запись кода результата обработки
- public void WriteInt(int answer)
- {
- byte[] outBuffer = new byte[1] { Convert.ToByte(answer) };
- ioStream.Write(outBuffer, 0, 1);
- ioStream.Flush();
- }
- //чтение кода результата обработки (если соединение разорвано на стороне сервера то вернёт -1).
- //Исключение выброшено не будет даже если поток закрыт!
- public int ReadInt()
- {
- return Convert.ToInt32(ioStream.ReadByte());
- }
- }
я не могу понять саму идею: как один поток сервера может обрабатывать несколько клиентов? Те как это он может пока один клиент висит получить данные от другого и ответить ему?
Объясните пожалуйста, с кодом было бы вообще идеально, но хотя бы на словах.Решение задачи: «Как один поток сервера может обрабатывать несколько клиентов»
textual
Листинг программы
- namespace Server
- {
- public class PipeServer
- {
- //количество потоков, пока что рассмотрим ситуацию когда = 1
- private int numThreads;
- //класс который хранит указатель на открытый канал и байты считанные с него
- private class ConnectionInfo
- {
- public NamedPipeServerStream pipeServer;
- public byte[] buffer;
- }
- public PipeServer(int numThreads)
- {
- this.numThreads = numThreads;
- }
- //запуск треда на выполнение
- public void Start()
- {
- //создаём экземпляр
- NamedPipeServerStream pipeServer =
- new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads,
- PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
- //асинхроонное ожидание подключения, при подключении будет вызвано AcceptCallback
- pipeServer.BeginWaitForConnection(new AsyncCallback(AcceptCallback), pipeServer);
- Console.WriteLine("\n*** Named pipe server stream started ***\n");
- Console.WriteLine("Waiting for client connect...\n");
- }
- //вызывается при подключении к серверу клиента
- /// <param name="result">указатель на открытый канал сервера</param>
- private void AcceptCallback(IAsyncResult result)
- {
- ConnectionInfo connection = new ConnectionInfo();
- connection.pipeServer = (NamedPipeServerStream)result.AsyncState;
- //объявляем об окончании ожидания (вроде так нужно тут сделать же?)
- connection.pipeServer.EndWaitForConnection(result);
- connection.buffer = new byte[1];//выделим место под информацию для получения от клиента
- //когда клиент подключился выведем уведомление об этом
- Console.WriteLine("{0} connected on thread[{1}].",
- connection.pipeServer.GetImpersonationUserName(), Thread.CurrentThread.ManagedThreadId);
- //начать АСИНХРОННОЕ чтение с потока
- connection.pipeServer.BeginRead(connection.buffer, 0, connection.buffer.Length,
- new AsyncCallback(ReceiveCallback), connection);
- //НАЧАТЬ АСИНХРОННОЕ ожидание след. подключеня не даёт - вываливается исключение что
- //канал уже находится в подключ. состоянии
- //connection.pipeServer.BeginWaitForConnection(new AsyncCallback(AcceptCallback), connection.pipeServer);
- }
- //вызывается при чтении данных с потока после подключения
- private void ReceiveCallback(IAsyncResult result)
- {
- ConnectionInfo connection = (ConnectionInfo)result.AsyncState;
- //считать данные
- StreamRW stream = new StreamRW(connection.pipeServer);
- Tuple<string, string> tuple = stream.ReadTuple(connection.buffer[0]);
- Console.WriteLine(tuple.Item1+" "+tuple.Item2);
- //записать АСИНХРОННО ответ
- connection.buffer = new byte[1] { 1 };
- connection.pipeServer.BeginWrite(connection.buffer, 0,
- connection.buffer.Length, SendCallback, connection);
- }
- //отправка ответа клиенту. пишеться АСИНХРОННО
- private void SendCallback(IAsyncResult result)
- {
- ConnectionInfo connection = (ConnectionInfo)result.AsyncState;
- connection.pipeServer.EndWrite(result);
- connection.pipeServer.Disconnect();
- connection.pipeServer.BeginWaitForConnection(new AsyncCallback(AcceptCallback),
- connection.pipeServer);
- }
- }
- class Test
- {
- static void Main(string[] args)
- {
- PipeServer pipe = new PipeServer(1);
- pipe.Start();
- Console.ReadLine();
- }
- }
- }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д