Я слышал о HTTP keep-alive, но сейчас я хочу открыть соединение сокета с удаленным сервером.
Теперь будет ли это соединение сокета оставаться открытым навсегда или с ним связано ограничение времени ожидания, подобное HTTP keep-alive?
Я слышал о HTTP keep-alive, но сейчас я хочу открыть соединение сокета с удаленным сервером.
Теперь будет ли это соединение сокета оставаться открытым навсегда или с ним связано ограничение времени ожидания, подобное HTTP keep-alive?
Ответы:
Сокеты TCP остаются открытыми, пока не будут закрыты.
Тем не менее, очень сложно обнаружить разорванное соединение (разорванное, поскольку маршрутизатор умер и т. Д., В отличие от закрытого) без фактической отправки данных, поэтому большинство приложений время от времени выполняют какую-то реакцию пинг / понг, чтобы убедиться, что связь все еще жива.
Теперь будет ли это соединение сокета оставаться открытым навсегда или с ним связано ограничение времени ожидания, подобное HTTP keep-alive?
Короткий ответ - нет, он не будет оставаться открытым вечно, он, вероятно, отключится через несколько часов. Поэтому да там есть тайм - аут , и это обеспечивается через TCP Keep-Alive .
Если вы хотите настроить тайм-аут Keep-Alive на вашем компьютере, см. Раздел «Изменение тайм-аута TCP» ниже. В противном случае прочитайте остальную часть ответа, чтобы узнать, как работает TCP Keep-Alive.
TCP-соединения состоят из двух сокетов, по одному на каждом конце соединения. Когда одна сторона хочет прервать соединение, она отправляетRST
пакет, который другая сторона подтверждает, и обе закрывают свои сокеты.
Однако до тех пор, пока это не произойдет, обе стороны будут держать свое гнездо открытым бесконечно. Это оставляет возможность того, что одна сторона может закрыть свой сокет намеренно или из-за какой-либо ошибки, не проинформировав другой конец через RST
. Для обнаружения этого сценария и закрытия устаревших соединений используется процесс TCP Keep Alive.
Есть три настраиваемых свойства, которые определяют, как работает Keep-Alives. В Linux их 1 :
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
Процесс работает так:
tcp_keepalive_time
нескольких секунд, отправьте один пустой ACK
пакет.1ACK
своим собственным?
tcp_keepalive_intvl
секунды, затем отправьте еще одинACK
ACK
отправленных зондов не станет равным tcp_keepalive_probes
.RST
и разорвите соединение.Этот процесс включен по умолчанию в большинстве операционных систем, и поэтому мертвые TCP-соединения регулярно удаляются, если другой конец не отвечает в течение 2 часов 11 минут (7200 секунд + 75 * 9 секунд).
Поскольку по умолчанию процесс не запускается, пока соединение не простаивает в течение двух часов, устаревшие TCP-соединения могут сохраняться очень долго, прежде чем будут отсечены. Это может быть особенно вредно для дорогостоящих соединений, таких как соединения с базой данных.
Согласно RFC 1122 4.2.3.6 , отвечать и / или ретранслировать пакеты TCP Keep-Alive необязательно :
Разработчики МОГУТ включать "keep-alive" в свои реализации TCP, хотя эта практика не является общепринятой. Если пакеты keep-alive включены, приложение ДОЛЖНО иметь возможность включать или выключать их для каждого TCP-соединения, и они ДОЛЖНЫ быть отключены по умолчанию.
...
Чрезвычайно важно помнить, что сегменты ACK, не содержащие данных, надежно не передаются TCP.
Причина в том, что пакеты Keep-Alive не содержат данных и не являются строго необходимыми, и при чрезмерном использовании рискуют засорить трубки интернета.
Однако на практике , по моему опыту, эта проблема со временем уменьшилась, поскольку пропускная способность стала дешевле; и поэтому пакеты Keep-Alive обычно не отбрасываются. Документация Amazon EC2, например, косвенно подтверждает Keep-Alive, поэтому, если вы размещаете на AWS, вы, вероятно, можете безопасно полагаться на Keep-Alive, но ваш опыт может отличаться.
К сожалению, поскольку TCP-соединения управляются на уровне ОС, Java не поддерживает настройку тайм-аутов на уровне сокетов, например в java.net.Socket
. Я нашел несколько попыток 3 использовать собственный интерфейс Java (JNI) для создания сокетов Java, которые вызывают собственный код для настройки этих параметров, но ни одна из них, похоже, не получила широкого признания или поддержки сообществом.
Вместо этого вы можете быть вынуждены применить вашу конфигурацию ко всей операционной системе. Имейте в виду, что эта конфигурация повлияет на все TCP-соединения, запущенные во всей системе.
Текущие настройки TCP Keep-Alive можно найти в
/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
Текущие настроенные параметры можно просмотреть с помощью 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 для подтверждения, но вы должны найти соответствующие настройки TCP Keep-Alive в реестре по адресу
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Сноски
1. См. man tcp
Дополнительную информацию.
2. Этот пакет часто называют пакетом «Keep-Alive», но в соответствии со спецификацией TCP это просто обычный ACK
пакет. Такие приложения, как Wireshark, могут пометить его как пакет «Keep-Alive» с помощью метаанализа порядковых номеров и номеров подтверждений, которые он содержит со ссылкой на предыдущие сообщения в сокете.
3. Некоторые примеры, которые я нашел при базовом поиске в Google, - это lucwilliams / JavaLinuxNet и flonatel / libdontdie .
$ no -a | grep tcp_keep
команды.
Вам нужен сокет SO_KEEPALIVE.
В API Java Торцевые обнажает «поддержания активности» для приложений через setKeepAlive
и getKeepAlive
методов.
РЕДАКТИРОВАТЬ: SO_KEEPALIVE реализован в стеках сетевых протоколов ОС без отправки каких-либо «реальных» данных. Интервал поддержания активности зависит от операционной системы и может настраиваться с помощью параметра ядра.
Поскольку данные не отправляются, SO_KEEPALIVE может проверять только работоспособность сетевого подключения, но не работоспособность службы, к которой подключен сокет. Чтобы протестировать последнее, вам нужно реализовать что-то, что включает отправку сообщений на сервер и получение ответа.
Поддержание активности TCP и HTTP - очень разные концепции. В TCP keepalive - это административный пакет, отправляемый для обнаружения устаревшего соединения. В HTTP keepalive означает постоянное состояние соединения.
Это из спецификации TCP,
Пакеты проверки активности ДОЛЖНЫ быть отправлены только в том случае, если для соединения не было получено никаких пакетов данных или подтверждения в течение определенного интервала. Этот интервал ДОЛЖЕН быть настраиваемым и ДОЛЖЕН по умолчанию составлять не менее двух часов.
Как видите, интервал поддержки активности TCP по умолчанию слишком велик для большинства приложений. Возможно, вам придется добавить поддержку активности в протокол вашего приложения.
HTTP/1.0
каждом запросе / ответе требовалось переподключение к серверу. Потому что HTTP/1.1
они представили Keep-Alive
заголовок, который можно использовать, чтобы заставить сервер не разрывать соединение после завершения обработки ответа, чтобы облегчить запрос дополнительных файлов и обеспечить «конвейерную обработку»; отправка нескольких запросов и ожидание возврата всех данных.
Если вы находитесь за маскирующим NAT (как в наши дни большинство домашних пользователей), существует ограниченный пул внешних портов, и они должны использоваться совместно TCP-соединениями. Поэтому маскирующие NAT склонны предполагать, что соединение было разорвано, если в течение определенного периода времени не было отправлено никаких данных.
Эта и другие подобные проблемы (где-то между двумя конечными точками) могут означать, что соединение больше не будет «работать», если вы попытаетесь отправить данные после разумного периода простоя. Однако вы можете не обнаружить этого, пока не попытаетесь отправить данные.
Использование сообщений поддержки активности как снижает вероятность прерывания соединения где-то на линии, а также позволяет вам быстрее узнать о разорванном соединении.
Вот некоторая дополнительная литература по поддержке активности, которая объясняет это более подробно.
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
Поскольку Java не позволяет вам контролировать фактическое время поддержки активности, вы можете использовать примеры, чтобы изменить их, если вы используете ядро Linux (или ОС на основе proc).
В JAVA Socket - TCP-соединения управляются на уровне ОС, java.net.Socket не предоставляет встроенной функции для установки тайм-аутов для пакетов keepalive на уровне сокета. Но мы можем включить опцию keepalive для java-сокета, но по умолчанию для обработки после устаревших tcp-соединений требуется 2 часа 11 минут (7200 секунд). По этой причине соединение будет оставаться доступным в течение очень долгого времени до очистки. Итак, мы нашли решение использовать Java Native Interface (JNI), который вызывает собственный код (c ++) для настройки этих параметров.
**** ОС Windows ****
В операционной системе Windows keepalive_time и keepalive_intvl можно настраивать, но tcp_keepalive_probes нельзя изменить. По умолчанию при инициализации сокета TCP устанавливается время ожидания проверки активности на 2 часа и интервал проверки активности на 1 секунду. Общесистемным значением тайм-аута проверки активности по умолчанию можно управлять с помощью параметра реестра KeepAliveTime, который принимает значение в миллисекундах.
В Windows Vista и более поздних версиях количество проверок активности (повторной передачи данных) установлено на 10 и не может быть изменено.
В Windows Server 2003, Windows XP и Windows 2000 значение по умолчанию для количества проверок активности - 5. Количество проверок активности можно контролировать. Для Windows библиотека Winsock IOCTLs используется для настройки параметров tcp-keepalive.
int WSAIoctl (SocketFD, // дескриптор, идентифицирующий сокет SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // указатель на структуру tcp_keepalive (DWORD) cbInBuffer, // длина входного буфера NULL, // размер выходного буфера 0, // размер выходной буфер (LPDWORD) lpcbBytesReturned, // количество байтов, возвращенных NULL, // структура OVERLAPPED NULL // процедура завершения);
ОС Linux
В Linux есть встроенная поддержка keepalive, которая необходима для включения сети TCP / IP для ее использования. Программы должны запрашивать контроль активности для своих сокетов с помощью интерфейса setsockopt.
int setsockopt (int socket, int level, int optname, const void * optval, socklen_t optlen)
Каждый клиентский сокет будет создан с использованием java.net.Socket. Идентификатор дескриптора файла для каждого сокета будет извлечен с использованием отражения java.
Для Windows согласно Microsoft docs