На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
    > Пинг. Определение оборвавшегося TCP подключения , Достаточно ли послать данные и подождать таймаута?
      Речь идет об обычных tcp-сокетах. Насколько я знаю, протокол TCP не предусматривает никаких пингов для определения оборвавшегося подключения. Если удаленная сторона отключилась, не предупредив нас в соответствии с TCP протоколом (скажем, удаленный комп просто жестко завис и никаких FIN-пакетов не отправил), то мы абэтам не узнаем. :'(
      Отсюда следует, что если программа должна определять "отвалившиеся" коннекты, то она должна сама "пинговать" время
      от времени все свои активные соединения. Я не знаю, предусматривает ли TCP генерацию ошибки в случае, если на пакет с данными не ответили. Из-за этого вытекает вопрос: достаточно ли будет просто отправить данные и подождать результата отправки? Или нужно запрограммировать на удаленной стороне пинг-ответ и ждать его (в случае, если он не пришел за Х секунд, форсировать отключение)?

      Добавлено
      Второй вопрос. Что ресурсозатратнее - читать Х байт или писать Х байт в сокет? Из этого я хочу сделать вывод о том, что лучше - пинговать клиентов с сервера и отключать в случае ошибки или пинговать сервер с клиентов и на сервере отключать тех, кто не пропинговал за ping_time*фактор_запаса_времени.
      Фактор запаса времени имеет такой смысл: если сервер ждет, что клиент должен пинговать его раз в 10 секунд,
      то отключать клиента (считать "точно мертвым") имеет смысл, скажем, если за 15 секунд не получено пинга, т.к.
      клиент не всегда успеет отправить пинг секунда в секунду (задержки сети). Тогда фактор запаса времени = x1.5
      Сообщение отредактировано: reinterpret_alexey -
        UPD: Пишу на бустах, сервак кроссплатформенный. Учитывать надо все системы.
          Цитата reinterpret_alexey @
          Насколько я знаю, протокол TCP не предусматривает никаких пингов для определения оборвавшегося подключения.

          Да, пингов нет.
          Но есть keepalive probe.
          На уровне сокетов
          Цитата
          SO_KEEPALIVE
          Эта опция указывает, должен ли TCP-протокол периодически передавать сообщение keepalive probe на соединенный сокет. Если адресат будет не в состоянии ответить на это сообщение, соединение считается разорванным. Значение опции имеет тип int; значение отличное от нуля означает "да". По умолчанию время ожидания для TCP-сокета – 120 минут, однако в принципе этот параметр допускает изменение или на приложение (например, сервер) возлагается обязанность самостоятельного регулирования реакции TCP-модуля на длительную неактивность партнера.

          На уровне модуля ТСР
          Цитата
          TCP_KEEPALIVE
          Устанавливает интервал времени между пакетами "keep alive" в секундах. Вначале следует активировать опцию SO_KEEPALIVE.
            Oleg2004,

            Параметры SO_KEEPALIVE (интервал и таймаут) настраиваются в разных ОС по-разному, в винде - через WSAIoctl (https://msdn.microsoft.com/ru-ru/library/wi...(v=vs.85).aspx), в linux - через /etc/sysctl.conf и /proc/sys/net/ipv4/tcp_keepalive_time. Нужны права администратора. Параметры по умолчанию - винде 2 часа таймаут и 1 секунда интервал. Это подходит для противодействия роутерам, отрубающим соединения по таймауту, но в для детекта "отвалившихся"
            клиентов не подходит.

            Сейчас уже проверил, что TCP при отправке данных распознает зависший удаленный хост и закрывает соединение.
            Поэтому делаю вывод, что необходимо только с каким-то интервалом отправлять любую порцию данных и расчитывать,
            что соединения, на других концах которых зависшие клиенты, будут автоматически закрыты. Как вы считаете, мои рассуждения
            верны?
            Сообщение отредактировано: reinterpret_alexey -
              Цитата reinterpret_alexey @
              Как вы считаете, мои рассуждения верны?

              Считаю, что не совсем. Зачем изобретать велосипед? Есть куча протоколов прикладного уровня, которые используют как транспорт TCP. Тот же POP3, SMTP, и т.д. Там сервер как правило отвечает либо "OK", либо отвечает порцией запрошенной информации. По вопросу данного топика - нужно лишь разработать свой протокол общения, а принципы обмена взять с выше обозначенных протоколов. Это ИМХО.
                Цитата reinterpret_alexey @
                Параметры SO_KEEPALIVE (интервал и таймаут) настраиваются в разных ОС по-разному, в винде - через WSAIoctl (https://msdn.microsoft.com/ru-ru/library/wi...(v=vs.85).aspx), в linux - через /etc/sysctl.conf и /proc/sys/net/ipv4/tcp_keepalive_time. Нужны права администратора. Параметры по умолчанию - винде 2 часа таймаут и 1 секунда интервал

                Ну это известно по умолчанию :)
                Тот факт, что эта порция данных посылается только через огромный промежуток времени, конечно сводит на нет реакцию на отвалившегося партнера.
                Цитата reinterpret_alexey @
                Это подходит для противодействия роутерам, отрубающим соединения по таймауту, но для детекта "отвалившихся"
                клиентов не подходит.

                Это рассуждение мне честно говоря не понятно.
                Сам термин KEEPALIVE подразумевает общение только с клиентом. Причем тут рутеры - мне непонятно тоже. Рутеры не лезут в протокол ТСР, они связаны с IP-маршрутизацией, т.е. тупо переадреуют IP-пакет по нужному маршруту. Не знаю, есть в протоколах маршрутизации таймеры, отслеживающие поток IP-пакетов от конкретных источников. Это просто нереально.
                Если почему то душа не лежит к KEEPALIVE, Стивенс предлагает в своей книге программу "проверки пульса" на основе посылки срочных данных.
                Вот его рассуждения по этому поводу:
                Цитата
                стр.634 Глава 21. Внеполосные данные
                21.5. Клиент-серверные функции проверки пульса
                Теперь мы разработаем несколько простых функций проверки пульса для наших эхо-сервера и эхо-клиента. Эти функции способны быстро выявить сбой как на самом узле, так и в канале связи с ним.
                Перед тем как рассматривать эти функции, мы хотели бы привести несколько советов по их применению. Некоторые программисты пытаются использовать для обеспечения этой функциональности параметр SO_КEEPALIVE сокета TCP. Но TCP не посылает собеседнику проверочное сообщение (keepalive probe), пока не пройдет 2 часа, в течение которых соединение будет оставаться неактивным. Узнав об этой особенности, многие обычно интересуются тем, как уменьшить время простоя до значительно более короткого промежутка (порядка секунд), чтобы быстрее обнаружить сбой. Хотя многие системы позволяют уменьшить значение параметров таймера при определении «жизнеспособности» собеседника, обычно эти параметры задаются для всего ядра, а не каждого сокета, так что их изменение повлияет на все сокеты, в которыех включен параметр SO_КEEPALIVE. Также можно добавить, что этот параметр исходно не был предназначен для данной цели (высокочастотный опрос, high-frequeency polling).
                Далее, временная потеря связи между двумя концами соединения не означает, что система вышла из строя. В TCP предусмотрена возможность учесть это обстоятельство, а в Беркли-реализации TCP перед тем, как разорвать соединение, предпринимаются попытки повторной передачи через 8-10 минут. Более новые протоколы маршрутизации IP (например, OSPF) способны онаружить сбой и, возможно, предложить альтернативный канал за более короткое время (возможно, порядка нескольких секунд). Поэтому для каждого конкретного приложения следует разобраться и решить, нужно ли закрывать соединение после того, как в течение 5 или 10 секунд от собеседника не был получен ответ.Для некоторых приложений требуется такая функциональность, но для 6ольшинства она не нужна.
                Для регулярного опроса собеседника мы будем использовать срочный режим TCP. Запросы будут посылаться каждую секунду, но максимальное время ожидания ответа мы ограничим 5 секундами. Эти параметры могут изменены приложением (в отличие от интервалов отправки проверочных сообщений при использовании SO_KEEPALIVE).
                В нашем примере клиент посылает внеполосный байт серверу раз в секунду, а сервер, приняв этот байт, посылает в подтверждение приема внеполосный байт клиенту. Каждая сторона должна получить извещение, если другая оказывается недоступна. И клиент, и сервер раз в секунду увеличивают на 1 значение своей переменной cnt, а при получении внеполосного байта обнуляют ее.

                Ну и тд...
                Сообщение отредактировано: Oleg2004 -
                  JoeUser

                  Цитата
                  Считаю, что не совсем. Зачем изобретать велосипед?


                  Так вы считаете, что рассуждения не совсем верны или механизм, которого они касаются, не целесообразен?

                  Цитата
                  Есть куча протоколов прикладного уровня, которые используют как транспорт TCP. Тот же POP3, SMTP, и т.д. Там сервер как правило отвечает либо "OK", либо отвечает порцией запрошенной информации.


                  Я правильно понимаю, что вы советуете нечто вроде: сделать подобие гарантированно работающего механизма проще, чем
                  разобраться в проблеме и написать свой? Если это, то отвечу, что в данном случае это не так; пинг - очень простая
                  задача и делать пересылку лишнего трафика просто потому, что так сделано где-то ещё - нецелесообразно. Зачем отсылать
                  ответ на пинг, если после посылки данных умершему хосту TCP и так определит, что хост умер?

                  Цитата
                  Это рассуждение мне честно говоря не понятно.


                  Хорошо, выкиньте про роутеры. SO_KEEPALIVE не подходит для определения, что удаленная сторона умерла (скажем, на хосте BSoD), потому что это раз в два часа, а нужно, скажем, чтобы умершие соединения не жили дольше 10 секунд.
                  Поэтому не лежит душа к SO_KEEPALIVE.

                  Цитата
                  Стивенс предлагает в своей книге программу "проверки пульса" на основе посылки срочных данных.


                  Тут опять идет речь о чтении ответа на пинг. Я пока не вижу веских причин делать это, потому что TCP и так скажет,
                  что хост не отвечает на send() и закроет соединение насильно. Читать ответ пинга не обязательно. Достаточно только его отправить. Но могут быть какие-то подводные камни. В случае которых чтение станет необходимо. Вот я и пытаюсь выяснить, есть ли такие камни.
                    Цитата reinterpret_alexey @
                    что лучше - пинговать клиентов с сервера и отключать в случае ошибки или пинговать сервер с клиентов и на сервере отключать тех, кто не пропинговал за ping_time*фактор_запаса_времени.
                    Фактор запаса времени имеет такой смысл: если сервер ждет, что клиент должен пинговать его раз в 10 секунд, то отключать клиента (считать "точно мертвым") имеет смысл, скажем, если за 15 секунд не получено пинга, т.к. клиент не всегда успеет отправить пинг секунда в секунду (задержки сети).

                    Вы уж меня извините, но я честное слово не могу "въехать" в эти рассуждения.
                    Поясню мое непонимание.
                    Слова "сервер,клиент" могут означать два разных объекта
                    1. Комп. Т.е. Компьютер выполняет роль сервера (клиента)
                    2. Программа сервера (клиента).
                    Пинг (это уровень ICMP)определяет лишь - "живой ли сам комп, включен и на нем работает стек TCP/IP"/ Пинг не может определить, что на компе-клиенте слетела (выключена, повисла) программа клиента.
                    Работает комп или нет - вот что определяет пинг. Все остальное ему фиолетово.
                    Да, пинг в некотором смысле может свидетельствовать об отпадении клиента. Но отсутствие ICMP-еха означает только что
                    1. Комп не работает ваще. 2. На компе файрволл блокирует получение эха-запроса.
                    И совсем другое дело - на работающем компе слетел клиент - отключился, завис, или просто пользователь про своего клиента забыл и пошел на пьянку.
                    Этого пинг не определит. Отсюда вывод - TCP имеет отношение только к программе.
                    Помните, есть такая ошибка при подключении - "CONNREFUSED"? Это просто означает, что на данном компе с правильным IP просто не включен сервер на заданном порту. И это обнаруживает только TCP, а не ICMP.
                    Так что скорее всего вам надо четко определиться с постановкой и про про пинг забыть. Впрочем, он, как я уже сказал, поможет только тогда, когда на той стороне нет включенного компа.
                      Oleg2004

                      Да, с терминами надо быть осторожнее, my fault. Под пингом имеется ввиду концепция пинга (проверки), а не конкретно ICMP ping-пакет.
                      У меня обычный TCP сервер и обычные клиенты. Представим, что это просто чат-сервер, пример из буста. Если у клиента,
                      который висит на сервере, возник BSoD - то сервер об этом не узнает, пока что-то не пошлет. Для него соединение открыто.
                      Серверу необходимо время от времени (раз в 10 секунд) уничтожать такие соединения. Варианта как это сделать у меня два.
                      1) Посылать клиенту раз в 10 секунд сообщение "привет, я пинг" и ждать ответа.
                      2) Посылать тоже самое и не ждать ответа.

                      Я остановился на варианте 2) потому, что ждать ответа не обязательно - если у клиента BSoD, то send() завершится с ошибкой timeout, т.к. не получит подтверждения о получении. Задача решена. Но поскольку в других программах ждут ответ на "привет, я пинг" и поскольку могут быть какие-то подводные камни, а слать лишний трафик тоже не хочется, стою перед выбором. Поэтому и спрашиваю: верны ли рассуждения? Достаточно ли просто послать и не читать?
                        reinterpret_alexey, я решал эту задачу, но с другого конца. Клиент мне обязан периодически посылать пакеты, если запросов не было больше определенного времени, то сервер разрывает соединение. Никаких подводных камней в этом решении не обнаружено.
                          Цитата reinterpret_alexey @
                          Серверу необходимо время от времени (раз в 10 секунд) уничтожать такие соединения. Варианта как это сделать у меня два.
                          1) Посылать клиенту раз в 10 секунд сообщение "привет, я пинг" и ждать ответа.
                          2) Посылать тоже самое и не ждать ответа.

                          В протоколе HTTP 1.0 это решалось просто - сервер отсылал ответ на запрос и рвал соединение.
                          В протоколе HTTP 1.1 есть поле Keepalive.
                          Если через 10 секунд нет нового запроса - соединение рвется сервером. Web-сервера могут регулировать это время.
                          У вас - типа чат.
                          Надо сделать нечто как в ватсапе. В нем видно - собеседник печатает ответ.
                          Значит можно ждать.
                          Не печатает - ждем пару секунд и рвем - или что то в этом духе.
                          Это один из вариантов.
                          Сообщение отредактировано: Oleg2004 -
                            Цитата reinterpret_alexey @
                            Я правильно понимаю, что вы советуете нечто вроде: сделать подобие гарантированно работающего механизма проще, чем
                            разобраться в проблеме и написать свой?

                            Именно - гарантированно работающего механизма.

                            Цитата reinterpret_alexey @
                            Если это, то отвечу, что в данном случае это не так; пинг - очень простая
                            задача и делать пересылку лишнего трафика просто потому, что так сделано где-то ещё - нецелесообразно. Зачем отсылать
                            ответ на пинг, если после посылки данных умершему хосту TCP и так определит, что хост умер?

                            Хм ... а "пинг" не лишний трафик? Смотря с какой стороны смотреть. Если у пинга есть функция "поддерживать соединение", значить трафик не лишний. В противном случае - лишний. Я предлагаю лишь серверу и клиенту вести именно диалог. Клиент "сказал", сервер "подтвердил". Если клиенту нужно поддерживать соединение - пусть отсылает команду типа уведомления. Например, в FTP-протоколе есть команда NOOP подобного назначения.
                              Цитата
                              Хм ... а "пинг" не лишний трафик?


                              Посылка сервером "пинга" - не лишний, потому что без неё сервер не узнает о том, что клиент завис. Посылка клиентом подтверждения - лишний. Клиенту поддерживать соединение не нужно. Нужно только серверу знать, что клиент завис.
                                Жесть.
                                Есть два человека, говорят по телефону.
                                Друг друга не видят.
                                Один что-то говорит.
                                Вопрос - как он узнает собеседник его слышит или нет если тот ничего не ответит?

                                Это я к тому, что клиенту явно конечно отвечать ничего не надо, но с точки зрения трафика данные назад шлются - это HANDSHAKE предусмотренный протоколом TCP чтобы отправитель знал что его данные получены.
                                Надо знать что вы там пишете, тогда можно что-то советовать.
                                А вообще у вас клиенты что, так часто зависают?
                                  Цитата
                                  Вопрос - как он узнает собеседник его слышит или нет если тот ничего не ответит?


                                  Он узнает так: ему скажут "Извините. Связь прервалась." Слышал такое не раз при звонке с мобильных 8-)
                                  Так же и мне TCP скажет: send() timeout, невозможно послать данные, сокет закрывается.
                                  Дело не в том, слушает клиент или не слушает. Он должен слушать и это определяется протоколом. Определять
                                  нарушение протокола не требуется. Необходимо только
                                  получить оповещение, что клиент более не в состоянии слушать (BSoD, к примеру).

                                  Цитата
                                  Надо знать что вы там пишете, тогда можно что-то советовать.


                                  Клиенты подключаются к серверу и ждут текста (сервер оповещает клиентов о некоторых изменениях). Подключение обязательно, разрывать его нельзя. На сервере нельзя больше 10 секунд не знать о том, что у клиента BSoD.
                                  Сообщение отредактировано: reinterpret_alexey -
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:
                                  Страницы: (3) [1] 2 3  все


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0607 ]   [ 17 queries used ]   [ Generated: 25.04.24, 15:18 GMT ]