Как правильно использовать опцию 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()
будет разблокирован, когда клиент не работает.
полное объяснение можно найти здесь.