Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Не получается отследить потерю связи по сети. Linux, сокеты.  (Прочитано 16161 раз)
0 Пользователей и 1 Гость смотрят эту тему.
demon051
Помогающий

ru
Offline Offline

« : 25-07-2018 13:43 » 

Всем привет.
Работаю с неблокирующими сокетами под Linux.

Не получается отследить ситуацию потери сети. Т.е., например, вынули разъем из сетевой карты.

метод
select(ss[0]+1, &read_fs, &write_fs, &error_fs, &rwe_timeout);

в этом случае сообщает всё время, что для записи готов дескриптор write_fs
результат вызова select = 1

в итоге не могу поймать переподключение клиента после восстановления связи по сети, т.к. всё время кручусь в цикле опроса дескрипторов и повода для выхода из него нет...

Как быть?
Записан
darkelf
Молодой специалист

ua
Offline Offline

« Ответ #1 : 25-07-2018 15:18 » 

Насколько я знаю, выдёргивание кабеля при помощи select() отследить нельзя. Если у Вас используется протокол TCP/IP, то можно включить SO_ KEEPALIVE и тогда сетевая подсистема сама периодически будет проверять соединение, правда там есть свой ньюанс - интервал опроса по-умолчанию - 2 часа, плюс, настраивается не под конкретное соединение, а на целиком на всю систему. В связи с этим обычно такого рода проверку реализуют на прикладном уровне, например, выполняя посылку специальных NOP или echo сообщений, которые соответственно заранее предусматривают в своём прикладном протоколе.
« Последнее редактирование: 25-07-2018 15:21 от darkelf » Записан
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 25-07-2018 17:11 » 

Извините, много букаф Улыбаюсь
Позволю себе процитировать замечательную, на мой взгляд, книженцию "Эффективное программирование TCP/IP" Йона Снейдера. Ее легко найти в сети в сканированном виде. Изумительно легко написана, очень подробно, а главное с примерами программирования и очень подробным разбором типичных источников ошибок и заблуждений, в том числе самой распространенной - о гарантированной доставке...

  Потенциальные ошибки.
 
  Вы уже видели одну из потенциальных ошибок при работе с TCP: не исключено, что
подтвержденные TCP данные не дошли до приложения-получателя. Как и большинство других
таких ошибок, это довольно редкая ситуация, и, даже если она встречается, последствия
могут быть не очень печальными. Важно, чтобы программист знал об этой неприятности и
предусматривал защиту при возможном нежелательном результате. Не думайте, что TCP обо
всем позаботится сам, следует подумать об устойчивости приложения.
  Защита от упомянутой ошибки очевидна. Если приложению-отправителю важно иметь
информацию, что сообщение дошло до приложения-получателя, то получатель должен сам
подтвердить факт приема. Часто такое подтверждение присутствует неявно. Например, если
клиент запрашивает у сервера некоторые данные и сервер отвечает, то сам ответ - это
подтверждение получения запроса.
  Более сложный для клиента вопрос - что делать, если сервер не подтверждает приема?
Это в основном зависит от конкретного приложения, поэтому готового Решения не существует.
Однако стоит отметить, что повторная посылка запроса не всегда годится.

  Рассмотрим некоторые типичные ошибки. Пока между двумя хостами существует связь,
TCP гарантирует доставку данных по порядку и без искажений. Ошибка может произойти только
при разрыве связи. Из-за чего же связь может разорваться? Есть три причины:
    - постоянный или временный сбой в сети;
    - отказ принимающего приложения;
    - аварийный сбой самого хоста на принимающем конце.
Каждое из этих событий по-разному отражается на приложении-отправителе.
  - Сбой в сети.
  Сбои в сети происходят по разным причинам: от потери связи с маршрутизатором или отрезком
опорной сети до выдергивания из разъема кабеля локальной Ethernet-сети.
При наличии у TCP ожидающего запроса на чтение операция возвращает ошибку, и переменная
errno устанавливается в ETIMEDOUT. Если ожидающего запроса на чтение нет, то следующая
операция записи завершится ошибкой. При этом либо будет послан сигнал SIGPIPE, либо (если
этот сигнал перехвачен или игнорируется) в переменную errno записано значение EPIPE.
Если промежуточный маршрутизатор не может переправить далее IР-датаграмму, содержащую
некоторый сегмент, то он посылает хосту - отправителю ICMP-сообшение о том, что сеть или
хост назначения недоступны. В этом случае некоторые реализации возвращают в качестве кода
ошибки значение ENETUNREACH или EHOSTUNREACH
  - Отказ приложения.
  А теперь разберемся, что происходит, когда аварийно или как-либо иначе завершается
приложение на другом конце соединения. Прежде всего следует понимать, что с точки зрения
вашего приложения аварийное завершение другого конца отличается от ситуации, когда
приложение на том конце вызывает функцию close (или closesocket, если речь идет о Windows),
а затем exit. В обоих случаях TCP на другом конце посылает вашему TCP сегмент FIN. FIN
выступает в роли признака конца файла и означает, что у отправившего его приложения нет
больше данных для вас. Это не значит, что приложение на другом конце завершилось или не
хочет принимать данные. Подробнее это рассмотрено в совете 16. Как приложение уведомляется
о приходе FIN (и уведомляется ли вообще), зависит от его действий в этот момент.
Правильно спроектированное приложение, конечно, не игнорирует ошибки, такая ситуация может
иметь место и в корректно написанных программах. Предположим, что приложение выполняет
подряд несколько операций записи без промежуточного чтения- Типичный пример - FTP. Если
приложение на другом конце «падает», то TCP посылает сегмент FIN. Поскольку данная программа
только пишет, но не читает, в ней не содержится информация о получении этого FIN. При отправке
следующего сегмента TCP на другом конце вернет RST. А в программе опять не будет никаких
сведений об этом, так как ожидающей операции чтения нет. При второй попытке записи после
краха отвечающего конца программа получит сигнал SIGPIPE, если этот сигнал перехвачен или
игнорируется - код ошибки EPIPE.
Такое поведение вполне типично для приложений, выполняющих многократную запись без чтения,
поэтому надо отчетливо представлять себе последствия. Приложение уведомляется только после
второй операции отправки данных завершившемуся партнеру. Но, так как предшествующая операция
привела к сбросу соединения, посланные ей данные были потеряны.
  - Kрax хоста на другом конце соединения.
  Последняя ошибка, которую следует рассмотреть, - это аварийный останов хоста на другом
конце. Ситуация отличается от краха хоста, поскольку TCP на другом конце не может с помощью
сегмента FIN проинформировать программу о то, что ее партнер уже не работает.
Пока хост на другом конце не перезагрузят, ситуация будет выглядеть как сбой в сети - TCP
удаленного хоста не отвечает. Как и при сбое в сети, TCP продолжает повторно передавать
неподтвержденные сегменты. Но в конце концов, если удаленный хост так и не перезагрузится,
то TCP вернет приложению код ошибки ETIMEDOUT.
А что произойдет, если удаленный хост перезагрузится до того, как TCP Прекратит попытки и
разорвет соединение? Тогда повторно передаваемые вами сегменты дойдут до перезагрузившегося
хоста, в котором нет никакой информации о старых соединениях. В таком случае спецификация
TCP [Postel 1981b] требует, чтобы принимающий хост послал отправителю RST. В результате
отправитель оборвет соединение, и приложение либо получит код ошибки ECONNRESET (если есть
ожидающее чтение), либо следующая операция записи закончится сигналов SIGPIPE или ошибкой
EPIPE.

  Для обнаружения потери связи с клиентом необязательно реализовывать пульсацию,
как это делалось в совете 10. Нужно всего лишь установить тайм-аут для операции чтения.
Тогда, если от клиента в течение определенного времени не поступает запросов, то сервер
может предположить, что клиента больше нет, и разорвать соединение. Так поступают многие
FTP-серверы. Это легко сделать, либо явно установив таймер, либо воспользовавшись
возможностями системного вызова select, как было сделано при реализации пульсации.


  Операция записи данных в TCP.
 
  В общем случае операция записи не блокирует процесс, если только буфер передачи TCP
не полон. Это означает, что после записи управление почти всегда быстро возвращается
программе. После получения управления нельзя ничего гарантировать относительно
местонахождения «записанных» данных. Как упоминается в совете 9, это имеет значение
для надежности передачи данных.
  С точки зрения приложения данные записаны. Поэтому, помня о гарантиях доставки,
предлагаемых TCP, можно считать, что информация дошла до другого конца.
В действительности, некоторые (или все) эти данные в момент возврата из операции записи
могут все еще стоять в очереди на передачу. И если хост или при­ложение на другом конце
постигнет крах, то информация будет потеряна.
  Если отправляющее приложение завершает сеанс аварийно, то TCP все равно будет пытаться
доставить данные.
  Еще один важный момент, который нужно иметь в виду, - это обработка ошибки записи.
Если при записи на диск вызов write не вернул код ошибки, то точно известно, что запись
была успешной.
  При работе с TCP получение кода ошибки от операции записи - очень редкое явление.
Поскольку операция записи возвращает управление до фактической от правки данных, обычно
ошибки выявляются при последующих операциях. Так как следующей операцией чаще всего
бывает чтение, предполагается, что ошибки записи обнаруживаются при чтении. Операция
записи возвращает лишь ошибки, очевидные в момент вызова, а именно:
    - неверный дескриптор сокета;
    - файловый дескриптор указывает не на сокет (в случае вызова send и родственных
      функций);
    - указанный при вызове сокет не существует или не подсоединен;
    - в качестве адреса буфера указан недопустимый адрес.
Причина большинства этих проблем - ошибка в программе. После завершения стадии
разработки они почти не встречаются. Исключение составляет код ошибки EPIPE (или сигнал
SIGPIPE), который свидетельствует о сбросе соедине­ния хостом на другом конце. Условия,
при которых такая ошибка возникает, обсуждались в совете 9 при рассмотрении краха
приложения-партнера.
  Применительно к TCP соединениям операцию записи лучше представлять себе как копирование
в очередь для передачи, сопровождаемое извещением TCP о появлении новых данных. Понятно,
какую работу TCP произведет дальше, но эти действия будут асинхронны по отношению к самой
записи.


  Аккуратное размыкание соединений.

  Например, клиент может соединиться с сервером, отправить серию запросов, а затем закрыть
свою половину соединения, предоставив тем самым серверу информацию, что больше запросов
не будет. Серверу для ответа клиенту, возможно, понадобится выполнить большой объем работы
и даже связаться с другими серве­рами, так что он продолжает посылать данные уже после того,
как клиент прекра­тил отправлять запросы. С другой стороны, сервер может послать в ответ
сколько угодно данных, так что клиент не определяет заранее, когда ответ закончится.
Поэтому сервер, вероятно, как и клиент, закроет свой конец соединения, сигнализи­руя о
конце передачи.
  После того как ответ на последний запрос клиента отправлен и сервер закрыл свой конец
соединения, TCP завершает фазу разрыва. Обратите внимание, что за­крытие соединения
рассматривается как естественный способ известить партнера о прекращении передачи данных.
По сути, посылается признак конца файла EOF.

  Теперь, когда вы познакомились с вызовом shutdown, посмотрите, как его можно использовать
для аккуратного размыкания соединения. Цель этой операции гарантировать, что обе стороны
получат все предназначенные им данные до того, соединение будет разорвано.
  Просто закрыть соединение в некоторых случаях недостаточно, поскольку могут быть потеряны
еще не принятые данные. Помните, что, когда приложение закрывает соединение, недоставленные
данные отбрасываются.
  Когда TCP получает от хоста на другом конце сегмент FIN, он сообщает об этом приложению,
возвращая нуль из операции чтения. Примеры приводятся в строке 45 листинга 3.1 и в строке
20 листинга 3.2, где путем сравнения кода возврата recv с нулем проверяется, получен
ли EOF. Часто возникает путаница, когда в ситуации, подобной той, что показана в листинге
3.1, используется системный вызов select. Когда приложение на другом конце закрывает
отправляющую сторону соедине­ния, вызывая close или shutdown либо просто завершая работу,
select возвращает управление, сообщая, что в сокете есть данные для чтения. Если приложение
при этом не проверяет EOF, то оно может попытаться обработать сегмент нулевой длины или
зациклиться, переключаясь между вызовами read и select.
  В сетевых конференциях часто отмечают, что «select свидетельствует о на­личии информации
для чтения, но в действительности ничего не оказывается». В действительности хост на другом
конце просто закрыл, как минимум, отправля­ющую сторону соединения, и данные, о присутствии
которых говорит select, -это всего лишь признак конца файла.
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
demon051
Помогающий

ru
Offline Offline

« Ответ #3 : 26-07-2018 05:27 » 

Насколько я знаю, выдёргивание кабеля при помощи select() отследить нельзя. Если у Вас используется протокол TCP/IP, то можно включить SO_ KEEPALIVE и тогда сетевая подсистема сама периодически будет проверять соединение, правда там есть свой ньюанс - интервал опроса по-умолчанию - 2 часа, плюс, настраивается не под конкретное соединение, а на целиком на всю систему. В связи с этим обычно такого рода проверку реализуют на прикладном уровне, например, выполняя посылку специальных NOP или echo сообщений, которые соответственно заранее предусматривают в своём прикладном протоколе.

спасибо. вариант с обменом служебными сообщениями лежит на поверхности...
но к сожалению, в протокол он не был заложен.
а чуваки, которые реализуют клиента теперь говорят, что менять ничего не хотят, выкручивайтесь, мол, сами как хотите.
конечно надавить на них можно и заставить доделать.
но вообще-то странно... неужели нельзя отследить потерю сети на своей стороне, без посылок клиенту?
под виндами на сколько помню такая возможность существовала, ну по крайней мере при разработке под визуалкой на шарпе с использованием стандартных классов .Net
Выдавалось событие с ошибкой при вытыкании кабеля...
Записан
demon051
Помогающий

ru
Offline Offline

« Ответ #4 : 26-07-2018 05:33 » 

Извините, много букаф Улыбаюсь
Позволю себе процитировать замечательную, на мой взгляд, книженцию "Эффективное программирование TCP/IP" Йона Снейдера. Ее легко найти в сети в сканированном виде. Изумительно легко написана, очень подробно, а главное с примерами программирования и очень подробным разбором типичных источников ошибок и заблуждений, в том числе самой распространенной - о гарантированной доставке...

  Потенциальные ошибки.
  
  Вы уже видели одну из потенциальных ошибок при работе с TCP: не исключено, что
подтвержденные TCP данные не дошли до приложения-получателя. Как и большинство других
таких ошибок, это довольно редкая ситуация, и, даже если она встречается, последствия
могут быть не очень печальными. Важно, чтобы программист знал об этой неприятности и
предусматривал защиту при возможном нежелательном результате. Не думайте, что TCP обо
всем позаботится сам, следует подумать об устойчивости приложения.
  Защита от упомянутой ошибки очевидна. Если приложению-отправителю важно иметь
информацию, что сообщение дошло до приложения-получателя, то получатель должен сам
подтвердить факт приема. Часто такое подтверждение присутствует неявно. Например, если
клиент запрашивает у сервера некоторые данные и сервер отвечает, то сам ответ - это
подтверждение получения запроса.
  Более сложный для клиента вопрос - что делать, если сервер не подтверждает приема?
Это в основном зависит от конкретного приложения, поэтому готового Решения не существует.
Однако стоит отметить, что повторная посылка запроса не всегда годится.

  Рассмотрим некоторые типичные ошибки. Пока между двумя хостами существует связь,
TCP гарантирует доставку данных по порядку и без искажений. Ошибка может произойти только
при разрыве связи. Из-за чего же связь может разорваться? Есть три причины:
    - постоянный или временный сбой в сети;
    - отказ принимающего приложения;
    - аварийный сбой самого хоста на принимающем конце.
Каждое из этих событий по-разному отражается на приложении-отправителе.
  - Сбой в сети.
  Сбои в сети происходят по разным причинам: от потери связи с маршрутизатором или отрезком
опорной сети до выдергивания из разъема кабеля локальной Ethernet-сети.
При наличии у TCP ожидающего запроса на чтение операция возвращает ошибку, и переменная
errno устанавливается в ETIMEDOUT. Если ожидающего запроса на чтение нет, то следующая
операция записи завершится ошибкой. При этом либо будет послан сигнал SIGPIPE, либо (если
этот сигнал перехвачен или игнорируется) в переменную errno записано значение EPIPE.
Если промежуточный маршрутизатор не может переправить далее IР-датаграмму, содержащую
некоторый сегмент, то он посылает хосту - отправителю ICMP-сообшение о том, что сеть или
хост назначения недоступны. В этом случае некоторые реализации возвращают в качестве кода
ошибки значение ENETUNREACH или EHOSTUNREACH
  - Отказ приложения.
  А теперь разберемся, что происходит, когда аварийно или как-либо иначе завершается
приложение на другом конце соединения. Прежде всего следует понимать, что с точки зрения
вашего приложения аварийное завершение другого конца отличается от ситуации, когда
приложение на том конце вызывает функцию close (или closesocket, если речь идет о Windows),
а затем exit. В обоих случаях TCP на другом конце посылает вашему TCP сегмент FIN. FIN
выступает в роли признака конца файла и означает, что у отправившего его приложения нет
больше данных для вас. Это не значит, что приложение на другом конце завершилось или не
хочет принимать данные. Подробнее это рассмотрено в совете 16. Как приложение уведомляется
о приходе FIN (и уведомляется ли вообще), зависит от его действий в этот момент.
Правильно спроектированное приложение, конечно, не игнорирует ошибки, такая ситуация может
иметь место и в корректно написанных программах. Предположим, что приложение выполняет
подряд несколько операций записи без промежуточного чтения- Типичный пример - FTP. Если
приложение на другом конце «падает», то TCP посылает сегмент FIN. Поскольку данная программа
только пишет, но не читает, в ней не содержится информация о получении этого FIN. При отправке
следующего сегмента TCP на другом конце вернет RST. А в программе опять не будет никаких
сведений об этом, так как ожидающей операции чтения нет. При второй попытке записи после
краха отвечающего конца программа получит сигнал SIGPIPE, если этот сигнал перехвачен или
игнорируется - код ошибки EPIPE.
Такое поведение вполне типично для приложений, выполняющих многократную запись без чтения,
поэтому надо отчетливо представлять себе последствия. Приложение уведомляется только после
второй операции отправки данных завершившемуся партнеру. Но, так как предшествующая операция
привела к сбросу соединения, посланные ей данные были потеряны.
  - Kрax хоста на другом конце соединения.
  Последняя ошибка, которую следует рассмотреть, - это аварийный останов хоста на другом
конце. Ситуация отличается от краха хоста, поскольку TCP на другом конце не может с помощью
сегмента FIN проинформировать программу о то, что ее партнер уже не работает.
Пока хост на другом конце не перезагрузят, ситуация будет выглядеть как сбой в сети - TCP
удаленного хоста не отвечает. Как и при сбое в сети, TCP продолжает повторно передавать
неподтвержденные сегменты. Но в конце концов, если удаленный хост так и не перезагрузится,
то TCP вернет приложению код ошибки ETIMEDOUT.
А что произойдет, если удаленный хост перезагрузится до того, как TCP Прекратит попытки и
разорвет соединение? Тогда повторно передаваемые вами сегменты дойдут до перезагрузившегося
хоста, в котором нет никакой информации о старых соединениях. В таком случае спецификация
TCP [Postel 1981b] требует, чтобы принимающий хост послал отправителю RST. В результате
отправитель оборвет соединение, и приложение либо получит код ошибки ECONNRESET (если есть
ожидающее чтение), либо следующая операция записи закончится сигналов SIGPIPE или ошибкой
EPIPE.

  Для обнаружения потери связи с клиентом необязательно реализовывать пульсацию,
как это делалось в совете 10. Нужно всего лишь установить тайм-аут для операции чтения.
Тогда, если от клиента в течение определенного времени не поступает запросов, то сервер
может предположить, что клиента больше нет, и разорвать соединение. Так поступают многие
FTP-серверы. Это легко сделать, либо явно установив таймер, либо воспользовавшись
возможностями системного вызова select, как было сделано при реализации пульсации.


  Операция записи данных в TCP.
  
  В общем случае операция записи не блокирует процесс, если только буфер передачи TCP
не полон. Это означает, что после записи управление почти всегда быстро возвращается
программе. После получения управления нельзя ничего гарантировать относительно
местонахождения «записанных» данных. Как упоминается в совете 9, это имеет значение
для надежности передачи данных.
  С точки зрения приложения данные записаны. Поэтому, помня о гарантиях доставки,
предлагаемых TCP, можно считать, что информация дошла до другого конца.
В действительности, некоторые (или все) эти данные в момент возврата из операции записи
могут все еще стоять в очереди на передачу. И если хост или при­ложение на другом конце
постигнет крах, то информация будет потеряна.
  Если отправляющее приложение завершает сеанс аварийно, то TCP все равно будет пытаться
доставить данные.
  Еще один важный момент, который нужно иметь в виду, - это обработка ошибки записи.
Если при записи на диск вызов write не вернул код ошибки, то точно известно, что запись
была успешной.
  При работе с TCP получение кода ошибки от операции записи - очень редкое явление.
Поскольку операция записи возвращает управление до фактической от правки данных, обычно
ошибки выявляются при последующих операциях. Так как следующей операцией чаще всего
бывает чтение, предполагается, что ошибки записи обнаруживаются при чтении. Операция
записи возвращает лишь ошибки, очевидные в момент вызова, а именно:
    - неверный дескриптор сокета;
    - файловый дескриптор указывает не на сокет (в случае вызова send и родственных
      функций);
    - указанный при вызове сокет не существует или не подсоединен;
    - в качестве адреса буфера указан недопустимый адрес.
Причина большинства этих проблем - ошибка в программе. После завершения стадии
разработки они почти не встречаются. Исключение составляет код ошибки EPIPE (или сигнал
SIGPIPE), который свидетельствует о сбросе соедине­ния хостом на другом конце. Условия,
при которых такая ошибка возникает, обсуждались в совете 9 при рассмотрении краха
приложения-партнера.
  Применительно к TCP соединениям операцию записи лучше представлять себе как копирование
в очередь для передачи, сопровождаемое извещением TCP о появлении новых данных. Понятно,
какую работу TCP произведет дальше, но эти действия будут асинхронны по отношению к самой
записи.


  Аккуратное размыкание соединений.

  Например, клиент может соединиться с сервером, отправить серию запросов, а затем закрыть
свою половину соединения, предоставив тем самым серверу информацию, что больше запросов
не будет. Серверу для ответа клиенту, возможно, понадобится выполнить большой объем работы
и даже связаться с другими серве­рами, так что он продолжает посылать данные уже после того,
как клиент прекра­тил отправлять запросы. С другой стороны, сервер может послать в ответ
сколько угодно данных, так что клиент не определяет заранее, когда ответ закончится.
Поэтому сервер, вероятно, как и клиент, закроет свой конец соединения, сигнализи­руя о
конце передачи.
  После того как ответ на последний запрос клиента отправлен и сервер закрыл свой конец
соединения, TCP завершает фазу разрыва. Обратите внимание, что за­крытие соединения
рассматривается как естественный способ известить партнера о прекращении передачи данных.
По сути, посылается признак конца файла EOF.

  Теперь, когда вы познакомились с вызовом shutdown, посмотрите, как его можно использовать
для аккуратного размыкания соединения. Цель этой операции гарантировать, что обе стороны
получат все предназначенные им данные до того, соединение будет разорвано.
  Просто закрыть соединение в некоторых случаях недостаточно, поскольку могут быть потеряны
еще не принятые данные. Помните, что, когда приложение закрывает соединение, недоставленные
данные отбрасываются.
  Когда TCP получает от хоста на другом конце сегмент FIN, он сообщает об этом приложению,
возвращая нуль из операции чтения. Примеры приводятся в строке 45 листинга 3.1 и в строке
20 листинга 3.2, где путем сравнения кода возврата recv с нулем проверяется, получен
ли EOF. Часто возникает путаница, когда в ситуации, подобной той, что показана в листинге
3.1, используется системный вызов select. Когда приложение на другом конце закрывает
отправляющую сторону соедине­ния, вызывая close или shutdown либо просто завершая работу,
select возвращает управление, сообщая, что в сокете есть данные для чтения. Если приложение
при этом не проверяет EOF, то оно может попытаться обработать сегмент нулевой длины или
зациклиться, переключаясь между вызовами read и select.
  В сетевых конференциях часто отмечают, что «select свидетельствует о на­личии информации
для чтения, но в действительности ничего не оказывается». В действительности хост на другом
конце просто закрыл, как минимум, отправля­ющую сторону соединения, и данные, о присутствии
которых говорит select, -это всего лишь признак конца файла.


ы-ы-ы....
Ку!
Спасиба, канешна, но при чем тут гарантированная доставка?

select никаких ошибок не возвращает.
мало того операция send послушно отправляет посылку в сокет при оторванном сетевом кабеле и возвращает  не 0, как следовало бы предполагать, а число равное кол-ву отправленных байт, т.е. длину посылки.

приложение на той стороне ничего не закрывает. ну вернее оно-то может и закрывает после отвала сети, но со стороны сервера об этом ничего не известно. нет никаких EOF и так далее.

кроме того, если успеть вставить сетевой кабель до того, как клиент зарубил свой сокет, то соединение и обмен данными восстанавливаются без всяких переподключений.
т.е. со стороны сервера надо отследить факт отключения от сети - не клиента, а самого сервера! чтобы корректно закрыть сокет и перейти в режим ожидания подключения.
выше предлагался вариант с обменом служебными сообщениями. это верный подход.
но он приводит к изменению протокола обмена. это можно сделать.
но может всё же есть способ отследить проблемы с сетью иным способом?
« Последнее редактирование: 26-07-2018 05:38 от demon051 » Записан
darkelf
Молодой специалист

ua
Offline Offline

« Ответ #5 : 26-07-2018 06:26 » 

Насколько я знаю, выдёргивание кабеля при помощи select() отследить нельзя. Если у Вас используется протокол TCP/IP, то можно включить SO_ KEEPALIVE и тогда сетевая подсистема сама периодически будет проверять соединение, правда там есть свой ньюанс - интервал опроса по-умолчанию - 2 часа, плюс, настраивается не под конкретное соединение, а на целиком на всю систему. В связи с этим обычно такого рода проверку реализуют на прикладном уровне, например, выполняя посылку специальных NOP или echo сообщений, которые соответственно заранее предусматривают в своём прикладном протоколе.

спасибо. вариант с обменом служебными сообщениями лежит на поверхности...
но к сожалению, в протокол он не был заложен.
а чуваки, которые реализуют клиента теперь говорят, что менять ничего не хотят, выкручивайтесь, мол, сами как хотите.
конечно надавить на них можно и заставить доделать.
но вообще-то странно... неужели нельзя отследить потерю сети на своей стороне, без посылок клиенту?
под виндами на сколько помню такая возможность существовала, ну по крайней мере при разработке под визуалкой на шарпе с использованием стандартных классов .Net
Выдавалось событие с ошибкой при вытыкании кабеля...

Можно попытаться проанализировать состояние link-а у карточки. Правда там есть ограничение - процесс, который это делает должен иметь права суперпользователя ака root. Но таким образом Вы проверите пропадание, например, link-а на своей карточке, но никак ни на карточке клиента, и не сможете отследить, что, например, перебит кабель за роутером, к которому, например, подключен сервер, на котором запущена Ваша задача.
« Последнее редактирование: 26-07-2018 06:31 от darkelf » Записан
demon051
Помогающий

ru
Offline Offline

« Ответ #6 : 26-07-2018 06:49 » 

Насколько я знаю, выдёргивание кабеля при помощи select() отследить нельзя. Если у Вас используется протокол TCP/IP, то можно включить SO_ KEEPALIVE и тогда сетевая подсистема сама периодически будет проверять соединение, правда там есть свой ньюанс - интервал опроса по-умолчанию - 2 часа, плюс, настраивается не под конкретное соединение, а на целиком на всю систему. В связи с этим обычно такого рода проверку реализуют на прикладном уровне, например, выполняя посылку специальных NOP или echo сообщений, которые соответственно заранее предусматривают в своём прикладном протоколе.

спасибо. вариант с обменом служебными сообщениями лежит на поверхности...
но к сожалению, в протокол он не был заложен.
а чуваки, которые реализуют клиента теперь говорят, что менять ничего не хотят, выкручивайтесь, мол, сами как хотите.
конечно надавить на них можно и заставить доделать.
но вообще-то странно... неужели нельзя отследить потерю сети на своей стороне, без посылок клиенту?
под виндами на сколько помню такая возможность существовала, ну по крайней мере при разработке под визуалкой на шарпе с использованием стандартных классов .Net
Выдавалось событие с ошибкой при вытыкании кабеля...

Можно попытаться проанализировать состояние link-а у карточки. Правда там есть ограничение - процесс, который это делает должен иметь права суперпользователя ака root. Но таким образом Вы проверите пропадание, например, link-а на своей карточке, но никак ни на карточке клиента, и не сможете отследить, что, например, перебит кабель за роутером, к которому, например, подключен сервер, на котором запущена Ваша задача.


спасибо огромное!

код
Код:
#include <stdio.h>        // printf
#include <string.h>       // strncpy
//#include <sys/socket.h> // AF_INET
#include <sys/ioctl.h>    // SIOCGIFFLAGS
#include <errno.h>        // errno
#include <netinet/in.h>   // IPPROTO_IP
#include <net/if.h>       // IFF_*, ifreq

#define ERROR(fmt, ...) do { printf(fmt, __VA_ARGS__); return -1; } while(0)

int CheckLink(char *ifname) {
    int state = -1;
    int socId = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (socId < 0) ERROR("Socket failed. Errno = %d\n", errno);

    struct ifreq if_req;
    (void) strncpy(if_req.ifr_name, ifname, sizeof(if_req.ifr_name));
    int rv = ioctl(socId, SIOCGIFFLAGS, &if_req);
    close(socId);

    if ( rv == -1) ERROR("Ioctl failed. Errno = %d\n", errno);

    return (if_req.ifr_flags & IFF_UP) && (if_req.ifr_flags & IFF_RUNNING);
}

int main() {
    printf("%d\n", CheckLink("eth0"));
}

работает.

этого пока достаточно. в случае возникновения других, в том числе и  описываемых вами ситуаций, будем менять протокол...
« Последнее редактирование: 26-07-2018 06:57 от demon051 » Записан
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 26-07-2018 08:09 » 

ы-ы-ы....
Ку!
Спасиба, канешна, но при чем тут гарантированная доставка?

select никаких ошибок не возвращает.
мало того операция send послушно отправляет посылку в сокет при оторванном сетевом кабеле и возвращает  не 0, как следовало бы предполагать, а число равное кол-ву отправленных байт, т.е. длину посылки.

приложение на той стороне ничего не закрывает. ну вернее оно-то может и закрывает после отвала сети, но со стороны сервера об этом ничего не известно. нет никаких EOF и так далее.

кроме того, если успеть вставить сетевой кабель до того, как клиент зарубил свой сокет, то соединение и обмен данными восстанавливаются без всяких переподключений.
т.е. со стороны сервера надо отследить факт отключения от сети - не клиента, а самого сервера! чтобы корректно закрыть сокет и перейти в режим ожидания подключения.
выше предлагался вариант с обменом служебными сообщениями. это верный подход.
но он приводит к изменению протокола обмена. это можно сделать.
но может всё же есть способ отследить проблемы с сетью иным способом?
Да, доставка, сама по себе тут не при чем, конечно. Просто, это один из распространенных мифов/заблуждений по теме...
Вот и надергал цитат, чтобы понятнее было, что книжка-то очень подробно тему описывает. Не более того.
Впрочем, Вы и сами в теме вполне достаточно, чтобы понять, что протокол спроектирован через то самое место Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 04-08-2018 09:53 » 

Рекомендую посмотреть в сторону dbus и networkmanager. Наверняка последний сообщает по шине о изменении состояния линков.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
demon051
Помогающий

ru
Offline Offline

« Ответ #9 : 06-08-2018 05:03 » new

Рекомендую посмотреть в сторону dbus и networkmanager. Наверняка последний сообщает по шине о изменении состояния линков.

да разобрались уже.
и состояние линка можем проверить и keepalive на конкретный сокет научились правильно настраивать...
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines