Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.14.253.221] |
|
Сообщ.
#1
,
|
|
|
В общем ситуация: есть сервер, есть 1 (не больше) клиент, который может быть подключен. Работа с cокетом на стороне сервера происходит в асинхронном режиме и вроде как проблем не было до недавнего времени... С клиентской стороны выглядит все так, как будто сервер перестает принимать соединение. Со стороны сервера, предположительно (пока точно не повторял ситуацию), не приходит FD_CLOSE. Собственно вопрос: FD_CLOSE обязан приходить, если, например, железно по питанию отрубили маршрутизатор, к которому подключен сервер или просто вытащили utp?
|
Сообщ.
#2
,
|
|
|
Нарывался на подобную проблему.Ситуация была такая, сервер и клиент на разных машинах, соединены не напрямую проводом, а через n - ое количество свитчей, маршрутизаторов и т.д. Если дернуть провод где-то "всередине", то на сервер не приходит FD_CLOSE, send ошибку не возвращает. Из решений можно либо ввести периодическую тестовую посылку, либо сделать отключение клиента при не активности(нет посылок в течение какого-то времени).
Если есть более правильное решение, то с радотсью о нем послушаю . |
Сообщ.
#3
,
|
|
|
Вот как все происходит:
Цитата • Событие FD_CLOSE: Действительно только для ориентированных на соединение сокетов (например SOCK_STREAM). 1. Когда происходит обращение к WSAAsyncSelect(), и в этот момент соединение по сокету уже закрыто. 2. После того, как удаленная система инициализировала нормальное завершение, и в буфере нет доступных данных. Имейте в виду, что, если данные был получены и ожидают считывания, и при этом удаленная система инициализирует нормальное завершение, FD_CLOSE не выдается, пока все ожидающие чтения данные не будут прочитаны. 3. После того как локальная система инициализировала нормальное завершение с помощью shutdown() и удаленная система ответила признаком "End of Data" (например, TCP FIN), и в буфере отсутствуют доступные данные. 4. Если удаленная система обрывает соединение (например шлет TCP RST), и lParam будет содержать значение ошибки WSAECONNRESET. Примечание FD_CLOSE не выдается после вызова closesocket(). Для посылки на противоположный конец сегмента FIN, по которому там возникнет FD_CLOSE, необходимо выполнить shutdown(). Т.е. говорить, что событие FD_CLOSE ПРИХОДИТ? нельзя. Грубо говоря, FD_CLOSE на компе, принимающем данные, возникает или при получении модулем TCP сегмента с флагом FIN, или при получении сегмента RST. Если по логике общения с сервером событие FD_CLOSE должно возникнуть, а его нет - то это ошибка в сети (все что угодно, крыса сожрала кабель) или сервер работает криво. Или вообще не работает |
Сообщ.
#4
,
|
|
|
Oleg2004, ну т.е. 100% гарантию регистрации потери связи может дать только контроль по таймауту?
|
Сообщ.
#5
,
|
|
|
По сути говоря да.
TCP весь построен на таймаутах и использует их очень интенсивно. Думаю даже простой пинг после правильно установленного таймаута уже даст результат. Если пинг проходит - значит умер сервер. Цитата Так как запрос клиента был выполнен TCP-модуль сервера отсылает клиенту сегмент FIN ACK. Флаг ACK подтверждает прием последней квитанции от клиента – тот правильно принял данные – последние байты файла, которые ему передал сервер. Получив приглашение закрыть соединение, клиент отвечает на посланный запрос своим АCK, переходит в состояние СLOSE_WAIT и посылает свой сегмент FIN ACK, переходя в состояние ожидания прихода последней квитанции (LAST_ ACK). Нормально работающий сервер обязан выдать сегмент FIN ACK. |
Сообщ.
#6
,
|
|
|
Oleg2004, спасибо!
Только все наоборот -- сервер это я. И мне нужно гарантированно узнать, когда отвалился клиент, включая случаи с всевозможными авариями с маршрутизаторами и проводами на пути следования пакетов. Добавлено Пока остановился на варианте FD_CLOSE + таймауты. |
Сообщ.
#7
,
|
|
|
Цитата shm @ С клиентской стороны выглядит все так, как будто сервер перестает принимать соединение. Со стороны сервера, предположительно (пока точно не повторял ситуацию), не приходит FD_CLOSE. Собственно вопрос: FD_CLOSE обязан приходить, если, например, железно по питанию отрубили маршрутизатор, к которому подключен сервер или просто вытащили utp? Но ведь в начальном посте вы обрисовали ситуацию несколько не так - см. болд. Цитата Будучи однажды создан, канал TCP может существовать "вечно". Если клиент и сервер пассивны, то при разрыве соединения, например, при проблемах со средой передачи, сетевой атаке, крахе сервера или клиента, участники соединения (либо один из них) не подозревают о возникших проблемах. Конечно, проблема рано или поздно будет выявлена - когда клиент или сервер попытаются послать какую-то информацию. В архитектуре клиент-сервер довольно часто встречаются реализации, в которых клиент, отправив запрос на сервер, долгое время ожидает ответа сервера. Еще более актуальная ситуация - в реализациях TCP-сервера необходимо точно знать, сколько из соединившихся клиентов реально существуют. Многие из прикладных протоколов применяют для этого "пустую операцию" (NOP), которая время от времени производится между клиентом и сервером для проверки наличия соединения. Данный подход хорош тем, что он не зависит от реализации стека TCP/IP. Есть и другой метод – таймер контроля работоспособности (keep-alive). Таймер контроля (keep-alive timer) вызывает периодическую выдачу сегментов без поля данных, а таймер разъединения (idle timer) задает максимальное время ожидания ответа. По истечении этого срока соединение считается разорванным. Как правило, период таймера контроля устанавливается на прикладном уровне, его значения лежат между 5 и 45 секундами. Максимальное время ожидания обычно принимается равным 360 секундам. Есть еще один способ: Цитата Можно привести еще одно важное применение "срочных" данных – так называемая "проверка пульса", предназначенная для выявления сбоя или в канале связи, или на хосте. Применение упоминавшейся опции SO_KEEPALIVE для этой цели возможно, но ограничено. Во-первых, по умолчанию ядро посылает пробный сегмент только через 2 часа неактивности партнера. Во-вторых, хотя некоторые системы и позволяют изменять этот параметр в меньшую сторону, это изменение касается всех сокетов всех приложений, где установлена опция SO_KEEPALIVE, что может быть нежелательно. Отсюда и следует практика применения передачи "срочных" данных, например 1 байт через каждую секунду, и ожидание ответа каждые 5 секунд. Пример есть у Стивенса. |
Сообщ.
#8
,
|
|
|
Цитата Oleg2004 @ Но ведь в начальном посте вы обрисовали ситуацию несколько не так - см. болд. Ну может ввел в заблуждение. "Со стороны сервера" я имел ввиду на сервере. |
Сообщ.
#9
,
|
|
|
Цитата shm @ Ну может ввел в заблуждение. А вот это в сетевом программировании наказуемо. Но надеюсь вы поняли суть. |
Сообщ.
#10
,
|
|
|
Цитата Oleg2004 @ Таймер контроля (keep-alive timer) вызывает периодическую Блин, точно! Я же сам когда-то давным-давно его использовал, но забыл про это... Полезно, когда протокол однонаправленный. Добавлено А так я реализовал просто проверку таймаута, т.к. по протоколу клиент обязан постоянно запрашивать данные. Если нск. секунд не спрашивает -- значит отвалился и я делаю shutdown + closesocket. |
Сообщ.
#11
,
|
|
|
Ну вот вроде бы проблема исчерпана...
|
Сообщ.
#12
,
|
|
|
Цитата Oleg2004 @ Ну вот вроде бы проблема исчерпана... Ну, в принципе, да. |