Comments 14
Насколько я помню, как минимум под Linux вечно соединение без данных жить не будет.
Оно схлопнется, когда истечет параметр net.netfilter.nf_conntrack_tcp_timeout_establishe
(по умолчанию: через 5 суток).
Так же есть еще SO_KEEPALIVE и SO_RCVTIMEO. Тогда соединение вообще будет вести себя предсказуемо, без гиганских задержек.
Я бы не стал полагаться на SO_KEEPALIVE. Там таймаут порядка 2-х часов.
В моей практике был прецедент: между серверами, которые держали неактивное соединение, находился statefull firewall и через час данные переставали через него проходить, хотя формально с обоих сторон соединение открыто.
Ну по дефолту действительно 2 часа:
cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
Если изменять системные параметры приемлемо, или 2 часа достаточно, то проблем нет. Если делаешь универсальный софт, который должен зарабоатть из коробки без настроек тогда да, надо пинговать самостоятельно.
Куда интереснее и печальнее ситуация, когда ребутящийся клиент обнаруживает, что сервер его больше не хочет принимать, потому что коннекты закончились, а предыдущие соединения висят часами, потому что сервер ничего не хочет слать клиенту просто так.
Вроде все правильно написано, но с другой стороны зачем? Классическая книга Ричарда Стивенса, изданная в 1994 году, покрывает эти и еще многие другие случаи гораздо подробнее и с детальным анализом tcpdump. Да она и написана интереснее на мой вкус.
Я надеялся увидеть обзор новых фишек TCP, которых с тех пор появилось множество и которые нигде систематически не описаны, но увы...
Только при изменении этого окна.
> надо послать ей «нулевые данные»
«Нулевые данные» невозможно послать средствами уровня сокетов. И противоположная сторона не обязана это подтверждать (она воспринимает такое просто как дежурный ACK). Единственный гарантированный способ получить ответ другой стороны — послать реальные данные.
В случае TCP — только на уровне сессии можно это лечить надёжно и кроссплатформенно (keepaliveʼами протокола уже выше уровнем, нежели TCP, тогда можно вводить собственный таймаут).
Снова обратите внимание — это истёкший тайм-аут read. Мы бы увидели ту же самую ошибку и при других операциях с сокетом. Это происходит потому, что сокет входит в состояние, когда истёк тайм-аут подключения. Причина этого в том, что удалённая сторона слишком долго не подтверждала пакет данных — 5 минут, в соответствии с настройками этой системы.
Где-то здесь будет повторная отправка данных с увеличивающимся интервалом (обычно интервал удваивается).
За этим лучше наблюдать не только по системным вызовам, но и по tcpdump.
Головоломки TCP