Как правильно использовать опцию so KEEPALIVE, чтобы определить, что клиент на другом конце не работает?

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

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

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

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

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

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

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

Спасибо за тонну заранее!!!

4 ответов


чтобы изменить количество зондов или интервалов зондирования, вы записываете значения в файловую систему /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 определил, что удаленный конец отключен.


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

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

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


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

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

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


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

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

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

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