На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Страницы: (3) 1 2 [3]  все  ( Перейти к последнему сообщению )  
    > Пинг. Определение оборвавшегося TCP подключения , Достаточно ли послать данные и подождать таймаута?
      Цитата reinterpret_alexey @
      уже было установлено, что TCP на одном из компьютеров (не обязательно сервер, это может быть и на клиенте)завершит recv() с ошибкой connection reset через 10 секунд (проверял на винде) после send()-а, который был сделан после того, как на другой стороне появился BSoD?
      Очевидно, не получив подтверждения о принятии, TCP считает коннект мертвым и обрывает recv()-ы с ошибкой connection reset.

      Вы уж меня извините, но выделенного я не понимаю.
      Давайте напишу, что же я все-таки понял в порядке времени событий:
      1. На той стороне произошел BSoD
      2. На нашей стороне об этом не знают и шлют данные send()'ом.
      3. На нашей же стороне сразу после send()(а эта функция выполняется очень быстро - она просто копирует данные из буфера приложения в буфер сокета) вызывается recv()
      4. recv()как будто не может ничего получить и завершается c ошибкой connection reset через 10 сек.
      Так развиваются события - или нет?
      Пока вы мне отвечаете, позволю себе пару соображений.
      Во первых, BSoD на партнере обозначает, что ВЕСЬ узел(хост) и его ОС больше не функционируют. Вообще. И никаких сегментов никуда слать не могут. Стивенс о таком случае пишет - мы не получаем ничего.
      Далее. К сожалению, я не нашел в сети, какое значение tcp_retries2, которое в Линкусе определяет, сколько раз повторно посылать TCP-сегмент при уже установленном соединении, до того как соединение будет считаться разорванным, применяется в Винде.
      К чему это я?
      По моему ваши 10 сек. очень похожи на прекращение передачи модулем TCP, который безуспешно пытается завершить передачу данных, полученных от send(), когда он не получил ACK на несколько повторных передач. И время 10 сек очень похоже на это.
      Т.е. я считаю что это ошибка именно после senda()
      Как тут возникает recv() я не понимаю.
        Цитата
        Так развиваются события - или нет?


        Нет. recv() не вызывается сразу после send()-а. recv() "висит" на протяжении всей сессии, потому что как только один recv() завершается, в completion handler-е завершения сразу же делается ещё один recv(). Это потому что в любой момент любая из сторон может что-то прислать. Но почему так важно в каком порядке что вызывается? Главное, что после десяти секунд мы увидим то же самое, что мы увидим при какой-то другой внезапной критической ошибке: соединение сбрасывается самим TCP. Как об этом можно узнать? Ну, например, ждущие данных recv() завершаются с ошибкой и пометкой: connection reset.
        Или send() начинает возвращать connection reset. Поэтому я думаю: безуспешная (нет ACK) попытка отправить что-то
        на BSoD-нувшую сторону через десять секунд заставляет TCP сбросить соединение.

        Соединение сбрасывается "на фоне", внутри TCP, после сброса (через ~десять секунд) все функции работы с сокетом об этом сигнализируют.
        Точно так же, как и в случае, если соединение насильно closesocket-нули на удаленной стороне (без graceful shutdown-а на удаленной стороне мы получим именно "соединение сброшено", тут так же).

        Цитата
        По моему ваши 10 сек. очень похожи на прекращение передачи модулем TCP, который безуспешно пытается завершить передачу данных, полученных от send(), когда он не получил ACK на несколько повторных передач. И время 10 сек очень похоже на это.


        Да, да, именно так.

        Цитата
        Т.е. я считаю что это ошибка именно после senda()
        Как тут возникает recv() я не понимаю.


        Не важно, какая операция завершается с ошибкой после того, как send() попытался послать данные на BSoD-нувший хост
        и, не дождавшись ACK, сбросил соединение, сигнализируя об ошибке. Главное - соединение сбрасывается.
        Просто в моем случае, как я уже указал выше,
        recv() работает постоянно, "слушая", не прислала ли что удаленная сторона. Поэтому первое, что вылетит с ошибкой -
        recv().

        Вот как я тестирую: я подключаюсь к серверу, работающему на vmware с реальной ОС и отправляю данные.
        Соединение установлено, всё ок. Далее я делаю BSoD на vmware. Реальная ОС об этом не знает и соединение продолжает
        висеть. Далее, уже после BSoD на vmware, я посылаю ей данные. Первые десять секунд всё это посылается
        и recv() тоже работает (просто ничего не читает). Проходит около десяти секунд и все, send() и recv() начинают
        возвращать ошибки.
        Обе ОС - винда.
        Сообщение отредактировано: reinterpret_alexey -
          Ну что ж, очень похоже на то, что я описал.
          И скорее всего все выглядит именно так - причина та, что достигнут порог при повторных передачах - от бсоднутого клиента АСК не приходят и система об этом сигнализирует. Тем более сколько я понимаю у вас сенд/ресив выполняются асинхронно.
            Цитата
            Тем более сколько я понимаю у вас сенд/ресив выполняются асинхронно.


            В конечном проекте конечно. При проверке, которую я описывал с BSoD-ом подходит и синхронный вариант.
              Ну и при синхронном тоже вроде все так.
              Можно проделать эксперимент - после сенда поставить слип секунд на 20.
                Oleg2004

                Раз мы друг друга поняли, то возвращаюсь к изначальному вопросу, которого отчасти уже, правда, коснулись.
                Не будет ли подводных камней вроде роутеров, маскирующих BSoD-нувшего клиента (отправляющего за него ACK-и) и
                подобного? Я собираюсь сделать такое "пингование send()-ом" в клиент-серверном приложении, похожем на IRC, давайте
                будем считать, что у меня аналог IRC.
                В IRC есть "понг", ответ на "пинг". А я вот, посмотрев на проблему, заметил, что pong тут вроде как не нужен.
                Решил сделать посылку в сервере, без чтения, надеясь на то, что клиенты "отвалятся сами" как обсуждалось выше.
                Хотелось бы понять насколько это будет норм.
                Сообщение отредактировано: reinterpret_alexey -
                  Цитата reinterpret_alexey @
                  В IRC есть "понг", ответ на "пинг". А я вот, посмотрев на проблему, заметил, что pong тут вроде как не нужен.

                  Тут мы подходим у ещё одному нюансу. Даже если нет BSoD, клиент может быть в состоянии "уж лучше б мёртв, чем жив". Вариант атаки на Ваш протокол отбросим, как маловероятный (но возможный - т.е. злонамеренный клиент коннектится, но ничего не делает кроме как забирает порт из пула входящих коннектов, в итоге много таких злых клиентов выжрут весь пул и остальным входящим будет возвращаться "птица обломинго"). Более вероятен сценарий затупившего клиента (то ли в ушедшего в бесконечный цикл, то ли ещё куда в силу багов, но отвечать "оно" пока что не в состоянии). Получается, что по гамбургскому счёту нужны и пинг, и понг - т.е. проверка адекватности клиента на той стороне. Если понг не приходит на несколько пингов подряд (при живом сокете), то можно объявить клиента выжившим из ума и дропнуть коннект. Заодно это решит и проблему с удерживаением "чернодырного" коннекта на маршрутизаторе.
                    Цитата reinterpret_alexey @
                    Не будет ли подводных камней вроде роутеров, маскирующих BSoD-нувшего клиента (отправляющего за него ACK-и) и
                    подобного?

                    Нет.
                    Рутеры никак не могут слать АСК :) Это разные уровни.
                    Про рутеры думаю надо забыть.
                    Они тут не причем - если только там нет man in the middle
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:
                    Страницы: (3) 1 2 [3]  все


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,5788 ]   [ 17 queries used ]   [ Generated: 19.04.24, 04:10 GMT ]