Проверка на стороне сервера, что клиент обработал отправленные данные - C#
Формулировка задачи:
Есть клиент и есть сервер, общаются по именованому каналу (named pipe)
Проблема: нужно сделать так чтобы сервер после записи данных в поток проверял прочитал ли их клиент и если не прочитал то давал ему на это время (допустим 500 мс, думаю этого достаточно) и если за это время клиент так и не считал данные то сервер разрывал подключение дабы поток не простаивал в ожидании.
Проблема в том что просто запись в поток всегда ждёт пока клиент завершит чтение (хоть он там и пол часа висеть будет и не захочет читать с потока данные), а асинхронная запись происходит сразу же и не даёт никакого доп. времени клиенту на чтение.
Из тех методов что нашёл у NamedPipeServerStream есть:
pipeServer.WaitForPipeDrain(); - никакого толку, ждёт завершение всех операций, те по сути считай что асинхронная запись превратилась в синхронную и опять возможен висяк потока на долгое время
WriteTimeout / ReadTimeout; - тоже никакого толку так как выбрасывается исключение что NamedPipeServerStream не поддерживает таких вещей.
Ещё конечно же остался вариант в сервере после записи данных написать:
Но это точно же не выход так как сервер будет точно висеть 500 мс, а клиент то может и через 10 мс уже давно всё считал с потока и его нужно было давным-давно закрыть.
Как в таких случаях поступают подскажите пожалуйста, ато сам я решение найти не смог.
Код моего сервера и клиента (асинхронные операции не используются пока что).
Моя обёртка через которую происходит чтение и запись в поток при общении между клиентом и сервером:
Сервер:
Клиент:
if(pipeServer.IsConnected) Thread.Sleep(500);
//класс для работы с потоком //Позволяет писать пары логин-пароль и считывать результаты их обработки 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()); } }
private static void ServerThread(object data) { //создаём именованный канал NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); //пара логин-пароль для получения инфо от клиента Tuple<string, string> logpass; //получим ID (просто для вывода на экран, больше не используется) int threadId = Thread.CurrentThread.ManagedThreadId; //сделаем вечный цикл чтобы сервер работал постоянно (ну почти постоянно) while (true) { //подождём подключения pipeServer.WaitForConnection(); //когда клиент подключился выведем уведомление об этом Console.WriteLine("Client connected on thread[{0}].", threadId); try { //настроим обёртку на канал StreamRW srw = new StreamRW(pipeServer); //получим связку логин-пароль logpass = srw.ReadData(); //покажем их на экран Console.WriteLine("Get from client on thread[{0}]: " + logpass.Item1 + " " + logpass.Item2, threadId); //отправим ответ клиенту srw.WriteInt(1); //выведем инфо что клиент отключился Console.WriteLine("Client on thread[{0}] disconnected.", threadId); } catch (IOException e) { Console.WriteLine("ERROR: {0}", e.Message); } //отсоединить клиента ибо нефиг тут висеть pipeServer.Disconnect(); } pipeServer.Close(); }
{ NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation); Console.WriteLine("Connecting to server...\n"); pipeClient.Connect(); //настроить обёртку на канал StreamRW srw = new StreamRW(pipeClient); //записать связку логин-пароль в поток srw.WriteData(new Tuple<string,string>("login","password")); //"зависнуть" на 5секунд чтобы продемонстрировать что сервер всё это время тоже висит и ничего не делает //в ожидании пока клиент не считает ответ об обработке данных (число int) Thread.Sleep(5000); //вывести ответ от сервера Console.Write(srw.ReadInt()); pipeClient.Close(); // Give the client process some time to display results before exiting. Thread.Sleep(4000); }
Решение задачи: «Проверка на стороне сервера, что клиент обработал отправленные данные»
textual
Листинг программы
Thread waitThread = new Thread(() => WaitForPipeDrain()); waitThread.Start(); bool isTerminated = waitThread.Join(500); if (isTerminated) { //все удачно отправилось } else { //клиент отвалился, можно прибить поток waitThread.Abort(); }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д