Имеет ли TCP-сокет соединение "keep alive"?
Я слышал о HTTP keep-alive, но сейчас я хочу открыть соединение сокета с удаленным сервером.
Теперь это соединение сокета останется открытым навсегда или с ним связан лимит времени ожидания, подобный HTTP keep-alive?
6 ответов:
TCP сокеты остаются открытыми, пока они не будут закрыты.
тем не менее, очень трудно обнаружить сломанное соединение (сломанное, как в маршрутизаторе, умершем и т. д., В отличие от закрытого) без фактической отправки данных, поэтому большинство приложений делают какую-то реакцию пинг-понга так часто, чтобы убедиться, что соединение все еще действительно живо.
теперь это соединение сокета останется открытым навсегда или с ним связан лимит времени ожидания, подобный HTTP keep-alive?
короткий ответ:да, есть тайм-аут, и он применяется через TCP Keep-Alive.
если вы хотите настроить время ожидания Keep-Alive, см. раздел "изменение таймаутов TCP" ниже.
введение
TCP-соединения состоят из двух розеток, одна на каждом конце соединения. Когда одна сторона хочет прервать соединение, она отправляет
RST
пакет, который другая сторона признает, и оба закрывают свои сокеты.до тех пор, пока это не произойдет, однако, обе стороны будут держать их сокет открытым на неопределенный срок. Это оставляет открытой возможность того, что одна сторона может закрыть свой сокет, намеренно или из-за некоторой ошибки, не сообщая другой конец через
RST
. Для обнаружения этого сценария и закрытия устаревших соединений Используется процесс TCP Keep Alive.Keep-Alive Process
есть три настраиваемых свойства, которые определяют, как Keep-Alives работают. На Linux они1:
tcp_keepalive_time
- по умолчанию 7200 секунд
tcp_keepalive_probes
- по умолчанию 9
tcp_keepalive_intvl
- по умолчанию 75 секунды
процесс работает следующим образом:
- клиент открывает TCP-соединение
- если соединение молчит для
tcp_keepalive_time
секунд, отправить один пустойACK
пакета.1- сервер ответил соответствующим
ACK
своего собственного?
- нет
- ждать
tcp_keepalive_intvl
секунд, а затем отправьте другойACK
- повторять до тех пор, пока число
ACK
зонды, которые были отправлены, равныtcp_keepalive_probes
.- если на данный момент не было получено ответа, отправьте
RST
и прекратить связь.- да: вернуться к Шагу 2
этот процесс включен по умолчанию в большинстве операционных систем, и поэтому мертвые TCP-соединения регулярно обрезаются, как только другой конец не отвечает в течение 2 часов 11 минут (7200 секунд + 75 * 9 секунд).
Gotchas
2 Часа По Умолчанию
поскольку процесс не запускается, пока соединение не простаивает в течение двух часов по умолчанию, устаревшие TCP-соединения могут задерживаться очень долго, прежде чем быть обрезаны. Это может быть особенно опасно для дорогих соединений, таких как соединения с базой данных.
Keep-Alive является необязательным
по данным RFC 1122 4.2.3.6, реагирование и / или ретрансляция TCP Keep-Alive packets необязательно:
разработчики могут включать "keep-alives" в свои реализации TCP, хотя эта практика не является общепринятой. Если держать-живы будут в комплекте, приложение должно быть в состоянии включить или выключить их для каждого TCP-соединение, и они должны по умолчанию отключаться.
...
это чрезвычайно важно помнить, что сегменты ACK, которые не содержат данных, не являются надежно передается по протоколу TCP.
рассуждение заключается в том, что пакеты Keep-Alive не содержат данных и не являются строго необходимыми и рискуют засорить трубки паутины, если их чрезмерно использовать.
однако на практике, мой опыт показывает, что эта проблема со временем уменьшилась, поскольку пропускная способность стала дешевле; и поэтому пакеты Keep-Alive обычно не отбрасываются. документация Amazon EC2 например, дает косвенное одобрение Keep-Alive, поэтому, если вы размещаете с AWS, вы, вероятно, безопасно полагаетесь на Keep-Alive, но ваш пробег может отличаться.
изменение таймаутов TCP
За Исполнение
к сожалению, поскольку TCP-соединения управляются на уровне ОС, Java не поддерживает настройку таймаутов на уровне сокетов, таких как in
java.net.Socket
. Я нашел несколько попыток3 чтобы использовать Java Native Interface (JNI) для создания сокетов Java, которые вызывают собственный код для настройки эти варианты, но ни один из них, по-видимому, не имеет широкого принятия или поддержки сообщества.вместо этого, вы можете быть вынуждены применить конфигурацию операционной системы в целом. Имейте в виду, что эта конфигурация будет влиять на все TCP-соединения, работающие на всей системе.
Linux
в настоящее время настроен протокол TCP удержание параметров может быть найден в
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
вы можете обновить любой из них следующим образом:
# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes $ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time # Send three Keep-Alive probes... $ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes # ... spaced 10 seconds apart. $ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl
такие изменения не будут сохраняться при перезапуске. Для внесения постоянных изменений используйте
sysctl
:sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Mac OS X
текущие настройки можно просмотреть с помощью
sysctl
:$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt" net.inet.tcp.keepidle: 7200000 net.inet.tcp.keepintvl: 75000 net.inet.tcp.keepcnt: 8
обратите внимание, Mac OS X определяет
keepidle
иkeepintvl
в единицах МС в отличие от Linux, который использует секунды.свойства могут быть установлены с помощью
sysctl
который сохранит эти настройки при перезагрузке:sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
кроме того, вы можете добавлять их в
/etc/sysctl.conf
(создает файл, если он не существует).$ cat /etc/sysctl.conf net.inet.tcp.keepidle=180000 net.inet.tcp.keepintvl=10000 net.inet.tcp.keepcnt=3
Windows
у меня нет машины Windows для подтверждения, но вы должны найти соответствующие настройки TCP Keep-Alive в реестре в
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
сноски
1. Смотрите
man tcp
для получения дополнительной информации.2. Этот пакет часто называют" Keep-Alive " пакет, но в спецификации TCP это просто обычный
ACK
пакета. Такие приложения, как Wireshark, могут помечать его как" живой " пакет путем мета-анализа последовательности и номеров подтверждения, которые он содержит в ссылка на предыдущие сообщения в сокете.3. Некоторые примеры, которые я нашел в основном поиске Google являются lucwilliams / JavaLinuxNet и flonatel / libdontdie.
вы ищете параметр сокета SO_KEEPALIVE.
The Java Socket API выставляет" keep-alive " для приложений через
setKeepAlive
иgetKeepAlive
методы.EDIT: SO_KEEPALIVE реализован в стеках сетевых протоколов ОС без отправки каких-либо" реальных " данных. Интервал поддержания активности зависит от операционной системы и может быть настроен с помощью параметра ядра.
поскольку данные не отправляются, SO_KEEPALIVE может только проверить живучесть сетевое подключение, а не живость службы, к которой подключен сокет. Чтобы проверить последнее, вам нужно реализовать что-то, что включает в себя отправку сообщений на сервер и получение ответа.
TCP keepalive и HTTP keepalive-это очень разные понятия. В TCP keepalive-это административный пакет, отправленный для обнаружения устаревшего соединения. В HTTP keepalive означает постоянное состояние соединения.
Это из спецификации TCP,
пакеты Keep-alive должны отправляться только в том случае, если в течение интервала не было получено никаких данных или пакетов подтверждения для соединения. Этот интервал должен быть конфигурируемым и по умолчанию должен быть не менее двух несколько часов.
Как вы можете видеть, по умолчанию TCP keepalive интервал слишком длинный для большинства приложений. Возможно, вам придется добавить активности в свой протокол.
Если вы находитесь за маскирующимся NAT (как и большинство домашних пользователей в эти дни), существует ограниченный пул внешних портов, и они должны быть общими для TCP-соединений. Поэтому маскирующиеся NATs, как правило, предполагают, что соединение было прервано, если данные не были отправлены в течение определенного периода времени.
эта и другие подобные проблемы (где-нибудь между двумя конечными точками) могут означать, что соединение больше не будет "работать", если вы попытаетесь отправить данные после разумного периода простоя. Тем не менее, вы не можете обнаружить это, пока вы попробовать для отправки данных.
используя keepalives оба уменьшается вероятность прерывания соединения где-то вниз по линии, а также позволяет узнать о сломанном соединении раньше.
вот некоторая дополнительная литература по keepalive, которая объясняет это гораздо более подробно.
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
поскольку Java не позволяет вам контролировать фактическое время поддержания активности, вы можете использовать примеры для их изменения, если вы используете ядро Linux (или ОС на основе proc).