Как правильно использовать параметр SO_KEEPALIVE, чтобы обнаружить, что клиент на другом конце не работает? - PullRequest
15 голосов
/ 25 марта 2011

поэтому я пытался изучить использование опции SO_KEEPALIVE в программировании сокетов на языке C в среде Linux.

Я создал серверный сокет и использовал свой браузер для подключения к нему.Это было успешно, и я смог прочитать запрос GET, но я застрял на использовании SO_KEEPALIVE.

Я проверил эту ссылку keepalive_description@tldg.org , но не смог найти ни одногопример, который показывает, как его использовать.

Как только я определяю запрос клиента по функции accept(), я устанавливаю значение опции SO_KEEPALIVE 1 на сокете клиента.Теперь я не знаю, как проверить, не работает ли клиент ?, Как изменить временной интервал между отправленными датчиками и т. Д.

Я имею в виду, как я получу сигнал о том, что клиент не работает (без чтения или записи вклиент ... Я думал, что получу некоторый сигнал, когда зонды не будут возвращены от клиента), как мне запрограммировать его после установки опции SO_KEEPALIVE.

Кроме того, если предположить, что зонды отправляются каждые 3 секунды, а клиент перестал работать, я не узнаю, что клиент не работает, и я могу получить SIGPIPE.

В любом случае, я хочу знатькак использовать SO_KEEPALIVE в коде.

За тонну заранее !!!

Ответы [ 4 ]

19 голосов
/ 25 марта 2011

Чтобы изменить количество зондов или интервалы между зондами, вы записываете значения в файловую систему / proc, например

 echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time
 echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl
 echo 20 > /proc/sys/net/ipv4/tcp_keepalive_probes

Обратите внимание, что эти значения являются глобальными для всех сокетов, поддерживающих keepalive, в системе. Вы также можете переопределить эти параметры для каждого сокета при установке setsockopt, см. Раздел 4.2 документа, который вы связали.

Вы не можете "проверить" состояние сокета из пространства пользователя с помощью keepalive. Вместо этого ядро ​​просто более агрессивно заставляет удаленный конец подтверждать пакеты и определяет, испортился ли сокет. Когда вы попытаетесь записать в сокет, вы получите SIGPIPE, если keepalive определил, что удаленный конец не работает.

10 голосов
/ 26 марта 2011

Вы получите тот же результат, если включите SO_KEEPALIVE, как если бы вы не включили SO_KEEPALIVE - обычно вы обнаружите, что сокет готов, и при чтении из него вы получите ошибку.

Вы можете установить тайм-аут активности активности для каждого сокета в Linux (это может быть специфичная для Linux функция). Я бы рекомендовал это, а не изменять общесистемные настройки. Для получения дополнительной информации см. Справочную страницу по tcp.

Наконец, если ваш клиент - веб-браузер, вполне вероятно, что он все равно довольно быстро закроет сокет - большинство из них будут поддерживать соединения keepalive (HTTP 1.1) только в течение относительно короткого времени (30 с, 1 мин и т. Д. ). Конечно, если клиентский компьютер исчез или сеть отключена (что SO_KEEPALIVE действительно полезно для обнаружения), он не сможет активно закрывать сокет.

3 голосов
/ 22 июня 2018

Краткий ответ, добавьте

int flags =1;
if (setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags))) { perror("ERROR: setsocketopt(), SO_KEEPALIVE"); exit(0); };

на стороне сервера, и read() будет разблокировано, когда клиент не работает.

Полное объяснение можно найти здесь .

2 голосов
/ 04 сентября 2012

Как уже обсуждалось, SO_KEEPALIVE делает ядро ​​более агрессивным в отношении постоянной проверки соединения, даже когда вы ничего не делаете, но не меняет или улучшает способ доставки информации вам. Вы узнаете, когда попробуете что-то действительно сделать (например, «написать»), и сразу же это выясните, поскольку ядро ​​теперь просто сообщает о состоянии ранее установленного флага, а не ждать нескольких секунд (или намного дольше в некоторых случаях) для сбоя сетевой активности. Та же самая кодовая логика, которая была у вас для обработки условия «другая сторона ушла неожиданно», все еще будет использоваться; что меняет время (не метод).

Практически каждая "практичная" программа для сокетов в некотором роде обеспечивает не -блокирующий доступ к сокетам во время фазы данных (возможно, с помощью select () / poll () или, возможно, с помощью fcntl () / O_NONBLOCK). / EINPROGRESS & EWOULDBLOCK, или, если ваше ядро ​​поддерживает это, возможно, с помощью MSG_DONTWAIT). Предполагая, что это уже сделано по другим причинам, тривиально (иногда вообще не требуется никакого кода), кроме того, сразу же узнать об обрыве соединения. Но если фаза данных не уже каким-то образом обеспечивает неблокирующий доступ к сокетам, вы не узнаете об обрыве соединения, пока в следующий раз не попробуете что-то сделать.

(Соединение с сокетом TCP без какого-либо неблокирующего поведения во время фазы данных общеизвестно хрупко, так как если неправильный пакет сталкивается с проблемой сети, программа очень легко потом "зависает" на неопределенное время, и нет много чего можно с этим поделать.)

...