Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/16: Рейтинг темы: голосов - 16, средняя оценка - 4.56
 Аватар для Gepar
1186 / 543 / 78
Регистрация: 01.07.2009
Сообщений: 3,517

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

25.10.2012, 12:07. Показов 3198. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть клиент и есть сервер, общаются по именованому каналу (named pipe)

Проблема: нужно сделать так чтобы сервер после записи данных в поток проверял прочитал ли их клиент и если не прочитал то давал ему на это время (допустим 500 мс, думаю этого достаточно) и если за это время клиент так и не считал данные то сервер разрывал подключение дабы поток не простаивал в ожидании.
Проблема в том что просто запись в поток всегда ждёт пока клиент завершит чтение (хоть он там и пол часа висеть будет и не захочет читать с потока данные), а асинхронная запись происходит сразу же и не даёт никакого доп. времени клиенту на чтение.

Из тех методов что нашёл у NamedPipeServerStream есть:
pipeServer.WaitForPipeDrain(); - никакого толку, ждёт завершение всех операций, те по сути считай что асинхронная запись превратилась в синхронную и опять возможен висяк потока на долгое время
WriteTimeout / ReadTimeout; - тоже никакого толку так как выбрасывается исключение что NamedPipeServerStream не поддерживает таких вещей.
Ещё конечно же остался вариант в сервере после записи данных написать:
C#
1
2
                    if(pipeServer.IsConnected)
                        Thread.Sleep(500);
Но это точно же не выход так как сервер будет точно висеть 500 мс, а клиент то может и через 10 мс уже давно всё считал с потока и его нужно было давным-давно закрыть.

Как в таких случаях поступают подскажите пожалуйста, ато сам я решение найти не смог.

Код моего сервера и клиента (асинхронные операции не используются пока что).
Моя обёртка через которую происходит чтение и запись в поток при общении между клиентом и сервером:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//класс для работы с потоком
//Позволяет писать пары логин-пароль и считывать результаты их обработки
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());
    }
}
Сервер:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 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();
        }
Клиент:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
            {
                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);
            }
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
25.10.2012, 12:07
Ответы с готовыми решениями:

Boost::Asio клиент - сервер: При вводе с телнета на стороне сервера появляется куча крякозябр
Раньше использовал Code::Blocks и winsock. Сейчас решил попробовать VS2013 и библиотеку boost::asio Проблема в передачи данных. Проверял...

Так поступают данные в программу обработчик находящююся на стороне сервера?
В программу-обработчик на стороне сервера поступают name=&quot;name&quot; value=&quot;value&quot; name = value value = 5 name = 5 Так ли поступают...

Нужно узнать, сколько времени пользователь провел на данной странице и затем записать данные в БД на стороне сервера.
Нужно узнать, сколько времени пользователь провел на данной странице и затем записать данные в БД на стороне сервера. Буду очень...

2
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
25.10.2012, 20:44
Если нет ожидания с таймаутом, то его всегда можно сэмулировать через потоки.
После отправки, создаете поток, в котором вызываете WaitForPipeDrain.
После чего ждете окончания потока с таймаутом.
C#
1
2
3
4
5
6
7
8
9
Thread waitThread = new Thread(() => WaitForPipeDrain());
waitThread.Start();
bool isTerminated = waitThread.Join(500);
if (isTerminated) {
   //все удачно отправилось
} else {
  //клиент отвалился, можно прибить поток
  waitThread.Abort();
}
1
 Аватар для Gepar
1186 / 543 / 78
Регистрация: 01.07.2009
Сообщений: 3,517
26.10.2012, 00:49  [ТС]
turbanoff, спасибо, сейчас попробую.

Добавлено через 2 часа 11 минут
В общем этот подход до конца не решает мои проблемы. Я как делаю: запускаю 4 потока сервера и они там себе ждут клинетов, в каждом есть while(true) так что после обслуживания очередного клиента как только он отключается поток сервера ждёт сл. клиента и так всё время.
Если я в main создам 4 потока и буду потом пользоваться описанным методом то возникает куча проблем. Во первых придёться теперь же завершать поток каждый раз так как иначе эта моя ловушка на зависший поток прибъёт его, она же не в курсе что он уже другого клиента обслуживает ну и в связи с этим появляются проблемы...
Смоделирую проблему: есть 4 потока, к каждому подключился какой-то клиент. 1 поток работает 400 мс, 2, 3 и 4 спраляются за 10мс. Так как в main у меня будет
bool isTerminated = waitThread.Join(500);
то перезапуск первого потока произойдёт через 500 мс (мейн ждёт завершения этой операции так что мейн "висит"), но так как перезапуск остальных потоков идёт после перезапуска первого то потоки 2, 3, 4 тоже висят 500 мс

Добавлено через 27 минут
В общем-то мне нужно что-то что будет пристреливать потоки которые повысли в ожидании, но если поток продолжает обработку то и трогать его не надо ... Другое дело как определять что он продолжает работу...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
26.10.2012, 00:49
Помогаю со студенческими работами здесь

В массив выводить данные-id клиента, данные серверу и данные, отправленные сервером
Здравствуйте. Имеется клиент-серверное приложение, вопрос по стороне сервера. Имеется backgroundworker-bw_clientReceining: ...

С сервера отправить данные на клиент
разобрался я более менее с сокетами но вот не как не получается с сервера отправить строчку на клиент реализуем о ли это ? а вот наоборот с...

Передать данные с сервера на клиент
Всем доброго времени суток. При выборе товара в таблице нужно получить его артикул и фирму из справочника номенклатура, скажите что не...

Клиент на Android не получает данные с сервера
Сервер на компе, написан на .Net, клиент на Android, ставится на устройство. Находясь в одной сети клиент подключается к серверу на .Net,...

Как правильно передавать данные с сервера на клиент (игра)
Добрый день. Есть структурированный список игроков(т.е. те кто онлайн) В цикле каждому юзеру(игроку), отправляю вот такую структуру, ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru