Проверка на стороне сервера, что клиент обработал отправленные данные - C#

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

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

Есть клиент и есть сервер, общаются по именованому каналу (named pipe) Проблема: нужно сделать так чтобы сервер после записи данных в поток проверял прочитал ли их клиент и если не прочитал то давал ему на это время (допустим 500 мс, думаю этого достаточно) и если за это время клиент так и не считал данные то сервер разрывал подключение дабы поток не простаивал в ожидании. Проблема в том что просто запись в поток всегда ждёт пока клиент завершит чтение (хоть он там и пол часа висеть будет и не захочет читать с потока данные), а асинхронная запись происходит сразу же и не даёт никакого доп. времени клиенту на чтение. Из тех методов что нашёл у NamedPipeServerStream есть: pipeServer.WaitForPipeDrain(); - никакого толку, ждёт завершение всех операций, те по сути считай что асинхронная запись превратилась в синхронную и опять возможен висяк потока на долгое время WriteTimeout / ReadTimeout; - тоже никакого толку так как выбрасывается исключение что NamedPipeServerStream не поддерживает таких вещей. Ещё конечно же остался вариант в сервере после записи данных написать:
                    if(pipeServer.IsConnected)
                        Thread.Sleep(500);
Но это точно же не выход так как сервер будет точно висеть 500 мс, а клиент то может и через 10 мс уже давно всё считал с потока и его нужно было давным-давно закрыть. Как в таких случаях поступают подскажите пожалуйста, ато сам я решение найти не смог. Код моего сервера и клиента (асинхронные операции не используются пока что). Моя обёртка через которую происходит чтение и запись в поток при общении между клиентом и сервером:
//класс для работы с потоком
//Позволяет писать пары логин-пароль и считывать результаты их обработки
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();
}

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


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

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

8   голосов , оценка 4 из 5
Похожие ответы