Как один поток сервера может обрабатывать несколько клиентов - 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(); } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д