На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > Непонятки с FD_CLOSE
      В общем ситуация: есть сервер, есть 1 (не больше) клиент, который может быть подключен. Работа с cокетом на стороне сервера происходит в асинхронном режиме и вроде как проблем не было до недавнего времени... С клиентской стороны выглядит все так, как будто сервер перестает принимать соединение. Со стороны сервера, предположительно (пока точно не повторял ситуацию), не приходит FD_CLOSE. Собственно вопрос: FD_CLOSE обязан приходить, если, например, железно по питанию отрубили маршрутизатор, к которому подключен сервер или просто вытащили utp?
      Сообщение отредактировано: shm -
        Нарывался на подобную проблему.Ситуация была такая, сервер и клиент на разных машинах, соединены не напрямую проводом, а через n - ое количество свитчей, маршрутизаторов и т.д. Если дернуть провод где-то "всередине", то на сервер не приходит FD_CLOSE, send ошибку не возвращает. Из решений можно либо ввести периодическую тестовую посылку, либо сделать отключение клиента при не активности(нет посылок в течение какого-то времени).
        Если есть более правильное решение, то с радотсью о нем послушаю ;).
          Вот как все происходит:
          Цитата
          • Событие 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 должно возникнуть, а его нет - то это ошибка в сети (все что угодно, крыса сожрала кабель) или сервер работает криво. Или вообще не работает :)
          Сообщение отредактировано: Oleg2004 -
            Oleg2004, ну т.е. 100% гарантию регистрации потери связи может дать только контроль по таймауту?
              По сути говоря да.
              TCP весь построен на таймаутах и использует их очень интенсивно.
              Думаю даже простой пинг после правильно установленного таймаута уже даст результат.
              Если пинг проходит - значит умер сервер.
              Цитата
              Так как запрос клиента был выполнен TCP-модуль сервера отсылает клиенту сегмент FIN ACK. Флаг ACK подтверждает прием последней квитанции от клиента – тот правильно принял данные – последние байты файла, которые ему передал сервер.
              Получив приглашение закрыть соединение, клиент отвечает на посланный запрос своим АCK, переходит в состояние СLOSE_WAIT и посылает свой сегмент FIN ACK, переходя в состояние ожидания прихода последней квитанции (LAST_ ACK).

              Нормально работающий сервер обязан выдать сегмент FIN ACK.
                Oleg2004, спасибо!
                Только все наоборот -- сервер это я. И мне нужно гарантированно узнать, когда отвалился клиент, включая случаи с всевозможными авариями с маршрутизаторами и проводами на пути следования пакетов.

                Добавлено
                Пока остановился на варианте FD_CLOSE + таймауты.
                Сообщение отредактировано: shm -
                  Цитата 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 секунд.

                  Пример есть у Стивенса.
                    Цитата Oleg2004 @
                    Но ведь в начальном посте вы обрисовали ситуацию несколько не так - см. болд.

                    Ну может ввел в заблуждение. "Со стороны сервера" я имел ввиду на сервере.
                      Цитата shm @
                      Ну может ввел в заблуждение.

                      А вот это в сетевом программировании наказуемо. :D
                      Но надеюсь вы поняли суть.
                        Цитата Oleg2004 @
                        Таймер контроля (keep-alive timer) вызывает периодическую

                        Блин, точно! Я же сам когда-то давным-давно его использовал, но забыл про это... :blush: Полезно, когда протокол однонаправленный.

                        Добавлено
                        А так я реализовал просто проверку таймаута, т.к. по протоколу клиент обязан постоянно запрашивать данные. Если нск. секунд не спрашивает -- значит отвалился и я делаю shutdown + closesocket.
                        Сообщение отредактировано: shm -
                          Ну вот вроде бы проблема исчерпана... :)
                            Цитата Oleg2004 @
                            Ну вот вроде бы проблема исчерпана...

                            Ну, в принципе, да.
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0311 ]   [ 16 queries used ]   [ Generated: 4.05.24, 17:51 GMT ]