2 заметки с тегом
c&cpp РСС
23 августа 2011, 18:40
Как определить, что клиент закрыл соединение
Мне тут на днях потребовалось в клиент-серверном коде моментально определить, закрыл ли клиент соединение или оно всё ещё держится. Решение требовалось сделать как на .NET так и на POSIX с помощью обычного C. Быстрый анализ различных документаций показал, что решения «в лоб» в виде вызова некоторой функции аля «getConnectionState(soket)» просто не существует ни в posix, ни в .NET.
Самое интересное, что по спецификации TCP этот протокол позволяет вполне точно определить когда клиент отсоединился. Речь конечно идёт о корректном завершении соединения, а не о физическом обрыве связи которое нельзя определить штатными средствами tcp протокола.
Требование к задаче следующее:т. к. в разные моменты времени в зависимости от контекста она сигнализирует о совершенно разных событиях в сокете/дискрипторе.
В нашем частном случае после того как соединение было успешно установлено, poll() возвращает true/non zero если сокет имеет данные, либо соединение разорвано (наша задача затем определить что именно произошло: пришли данные или соединение закрыто). В противном случае по таймауту возвращает false/zero (т. е. за время таймаута событий в сокете не случилось). Если к примеру сокет находится только в состоянии установки соединения, то результат возвращённый poll() будет указывать на другие события связанные с сокетом. Это стоит помнить.
Теперь код.
C#:
С/С++:
Приведенный выше код прекрасно отрабатывает и мгновенно отлавливает ситуации когда клиент закрывает соединение.
Ну и в заключение хочется сказать, что данные куски кода были написаны для внутренних тестирующих утилит и посему к ним никаких сверх требований не предъявлялось, как следствие вероятно их можно даже оптимизировать.
Happy coding! =)
Самое интересное, что по спецификации TCP этот протокол позволяет вполне точно определить когда клиент отсоединился. Речь конечно идёт о корректном завершении соединения, а не о физическом обрыве связи которое нельзя определить штатными средствами tcp протокола.
Требование к задаче следующее:
- Должна быть функция которая гарантированно получает N байт из сокета.
- Функция должна без промедлений определять отвалившегося клиента.
- .NET C# версия должна выбрасывать свой ConnectionLostException в случае разрыва соединения.
- POSIX C/C++ версия должна возвращать количество полученных байт или ноль в случае разрыва соединения.
В нашем частном случае после того как соединение было успешно установлено, poll() возвращает true/non zero если сокет имеет данные, либо соединение разорвано (наша задача затем определить что именно произошло: пришли данные или соединение закрыто). В противном случае по таймауту возвращает false/zero (
Теперь код.
C#:
- static public void ReceiveBytes(Socket sock, byte[] data)
- {
- int totalReceived = 0;
- int size = data.Length;
- // Цикл до тех пор пока не получим все данные
- while (totalReceived < size)
- {
- // Ждём 0.1 секунду события: или новые данные или обрыв
- if (sock.Poll(100000, SelectMode.SelectRead))
- {
- // Проверяем есть ли какие-то данные у сокета для нас
- if (sock.Available == 0)
- {
- // Данных нет, но раз Poll() вернул true — это обрыв
- // поэтому бросаем свой ConnectionLostException
- throw new ConnectionLostException();
- }
- try
- {
- // Получаем данные
- totalReceived += sock.Receive(data, totalReceived /* offset */,
- size - totalReceived /* size to recieve */,
- SocketFlags.None);
- }
- catch (SocketException ex)
- {
- // В зависимости от того как сконфигурирован сокет
- // мы можем поймать таймаут или попытку заблокировать сокет
- if (ex.SocketErrorCode == SocketError.TimedOut ||
- ex.SocketErrorCode == SocketError.WouldBlock)
- {
- // Это не критично и мы продолжаем цикл
- continue;
- }
- else
- {
- // Остальные исключения говорят о какой-то ошибке
- break;
- }
- }
- }
- }
- }
С/С++:
- int recieveData(int socket, void * buffer, int size)
- {
- int totalRecieved = 0, arrived = 0;
- struct pollfd pfd;
- // Подготавливаем структуру для вызова функции poll()
- pfd.fd = socket; // Указываем дискриптор сокета который интересует
- pfd.events = POLLIN | POLLHUP | POLLRDNORM;
- // Цикл пока не получим все данные
- while(totalRecieved < size)
- {
- // Ожидаем событие в сокете с таймаутом 100 миллисекунд
- if(poll(&pfd, 1, 100) > 0)
- {
- // Произошло какое-то событие — пытаемся получить данные
- arrived = recv(socket, (char*)buffer + totalRecieved, size - totalRecieved, MSG_DONTWAIT);
- // Если данных не пришло после того как poll() вернул не нулевой
- // результат — это означает только обрыв соединения
- if(arrived == -1 || totalRecieved == arrived)
- {
- // Сбрасываем счётчик полученных данных, что скажет об разрыве соединения
- totalRecieved = 0;
- break;
- }
- // Продолжаем получать данные
- totalRecieved += arrived;
- }
- }
- return totalRecieved;
- }
Приведенный выше код прекрасно отрабатывает и мгновенно отлавливает ситуации когда клиент закрывает соединение.
Ну и в заключение хочется сказать, что данные куски кода были написаны для внутренних тестирующих утилит и посему к ним никаких сверх требований не предъявлялось, как следствие вероятно их можно даже оптимизировать.
Happy coding! =)
нет комментариев
17 июля 2011, 18:08
Возможно самое короткое преобразование в bool
В нашем текущем проекте мы портируем WebKit под проект заказчика и приходится крайне много копаться в эппловском WebKit’е и немного в гуглевском Chromiume. Сколько бы я не занимался C++ , я постоянно нахожу что-то интересное. Поскольку chromium пишут достаточно серьёзные спецы, то я периодически наталкиваюсь на занимательные (на мой взгляд) куски кода на которых можно поучиться.
Так например совсем недавно я увидел выражение вида:
return !!count;
В первую секунду было удивление, а в следующую секунду стало понятно, что эта запись преобразует любое числовое значение к bool. Очень лаконично и красиво как по мне, вместо привычного:
return (bool)count;
В принципе такое преобразование должно так же работать в java, c#, да и наверное во всех производных от С языках.
Happy coding! =)
Так например совсем недавно я увидел выражение вида:
return !!count;
В первую секунду было удивление, а в следующую секунду стало понятно, что эта запись преобразует любое числовое значение к bool. Очень лаконично и красиво как по мне, вместо привычного:
return (bool)count;
В принципе такое преобразование должно так же работать в java, c#, да и наверное во всех производных от С языках.
Happy coding! =)
