Содержит ли соединение сокетов TCP "поддерживать"?

Я слышал о HTTP-поддержке, но на данный момент я хочу открыть сокет-соединение с удаленным сервером.
Теперь будет ли это соединение сокетов оставаться открытым навсегда или существует ли ограничение тайм-аута, связанное с ним, похожее на HTTP keep-alive?

Ответ 1

Сокеты TCP остаются открытыми до тех пор, пока они не будут закрыты.

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

Ответ 2

Теперь будет ли это соединение сокета оставаться открытым навсегда или существует ли ограничение тайм-аута, связанное с ним, похожее на HTTP keep-alive?

Короткий ответ: да, есть тайм-аут, и он применяется через TCP Keep-Alive.

Если вы хотите настроить тайм-аут Keep-Alive, см. Раздел "Изменение тайм-аутов TCP" ниже.

Вступление

Соединения TCP состоят из двух сокетов, по одному на каждом конце соединения. Когда одна сторона хочет завершить соединение, он отправляет пакет RST который подтверждает другая сторона, и оба закрывают свои сокеты.

Однако, пока это не произойдет, обе стороны будут держать свою розетку открытой на неопределенный срок. Это оставляет открытой возможность того, что одна сторона может закрыть свою розетку, преднамеренно или из-за некоторой ошибки, не сообщая другой конец через RST. Чтобы обнаружить этот сценарий и закрыть устаревшие соединения, используется процесс TCP Keep Alive.

Продолжающийся процесс

Существует три настраиваемых свойства, которые определяют, как Keep-Alives работают. В Linux они равны 1:

  • tcp_keepalive_time
    • по умолчанию 7200 секунд
  • tcp_keepalive_probes
    • по умолчанию 9
  • tcp_keepalive_intvl
    • по умолчанию 75 секунд

Процесс работает следующим образом:

  1. Клиент открывает TCP-соединение
  2. Если соединение tcp_keepalive_time для tcp_keepalive_time секунд, отправьте один пустой ACK пакет. 1
  3. Ответил ли сервер соответствующим ACK?
    • нет
      1. Подождите tcp_keepalive_intvl секунд, затем отправьте еще один ACK
      2. Повторяйте до тех пор, пока количество переданных ACK зондов не будет равно tcp_keepalive_probes.
      3. Если в этот момент ответа не получено, отправьте RST и завершите соединение.
    • Да: возврат к шагу 2

Этот процесс включен по умолчанию для большинства операционных систем, и, таким образом, мертвые TCP-соединения регулярно обрезаются, когда другой конец не реагирует на 2 часа 11 минут (7200 секунд + 75 * 9 секунд).

Gotchas

2 часа по умолчанию

Поскольку процесс не запускается до тех пор, пока соединение не будет работать в течение двух часов по умолчанию, устаревшие TCP-соединения могут задерживаться очень долго, прежде чем их обрезать. Это может быть особенно вредно для дорогостоящих соединений, таких как соединения с базой данных.

Keep-Alive является необязательным

Согласно RFC 1122 4.2.3.6, ответ на и/или передачу пакетов TCP Keep-Alive является необязательным:

Разработчики МОГУТ включать "keep-alives" в свои реализации TCP, хотя эта практика не является общепринятой. Если включены keep-alives, приложение ДОЛЖНО иметь возможность включать или выключать их для каждого TCP-соединения, и они ДОЛЖНЫ по умолчанию отключиться.

...

Крайне важно помнить, что сегменты ACK, которые не содержат данных, не надежно передаются TCP.

Причиной тому является то, что пакеты Keep-Alive не содержат данных и не являются строго необходимыми и могут засорять трубки межслоев при чрезмерном использовании.

На практике, однако, мой опыт заключается в том, что эта проблема со временем сократилась, поскольку пропускная способность стала дешевле; и, таким образом, пакеты Keep-Alive обычно не удаляются. Например, документация Amazon EC2 дает косвенное подтверждение Keep-Alive, поэтому, если вы размещаете с помощью AWS, вы, вероятно, будете в безопасности, полагаясь на Keep-Alive, но ваш пробег может отличаться.

Изменение тайм-аутов TCP

В гнезде

К сожалению, поскольку TCP-соединения управляются на уровне ОС, Java не поддерживает настройку тайм-аутов на уровне каждого сокета, например, в java.net.Socket. Я нашел несколько попыток 3 использовать Java Native Interface (JNI) для создания сокетов Java, которые вызывают собственный код для настройки этих параметров, но ни один из них не имеет широкого распространения или поддержки сообщества.

Вместо этого вы можете принудительно применить свою конфигурацию к операционной системе в целом. Имейте в виду, что эта конфигурация повлияет на все TCP-соединения, запущенные во всей системе.

Linux

Текущие настройки 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

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-компьютера для подтверждения, но вы должны найти соответствующие настройки Keep-Alive TCP в реестре на

\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.

Ответ 3

Вы ищете опцию сокета SO_KEEPALIVE.

Java Socket API предоставляет "keep-alive" приложениям с помощью методов setKeepAlive и getKeepAlive.

EDIT: SO_KEEPALIVE реализуется в стеках сетевых протоколов ОС без отправки каких-либо "реальных" данных. Интервал keep-alive зависит от операционной системы и может настраиваться с помощью параметра ядра.

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

Ответ 4

TCP keepalive и HTTP keepalive - это очень разные понятия. В TCP, keepalive - это административный пакет, отправленный для обнаружения устаревшего соединения. В HTTP keepalive означает постоянное состояние соединения.

Это из спецификации TCP,

Пакеты Keep-alive ДОЛЖНЫ быть отправлены только в том случае, если для соединения в течение интервала не было получено никаких пакетов данных или подтверждения. Этот интервал ДОЛЖЕН быть настраиваемым и ДОЛЖЕН использоваться по умолчанию не менее двух часов.

Как вы можете видеть, интервал постоянных транзакций по умолчанию для большинства приложений слишком длинный. Возможно, вам придется добавить keepalive в свой протокол приложений.

Ответ 5

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

Эта и другие подобные проблемы (в любом месте между двумя конечными точками) могут означать, что соединение больше не "работает", если вы попытаетесь отправить данные после разумного периода ожидания. Однако вы не сможете обнаружить это, пока не попытаетесь отправить данные.

Использование keepalives уменьшает вероятность прерывания соединения где-то вниз по линии, а также позволяет быстрее узнать о поврежденном соединении.

Ответ 6

Вот еще дополнительная литература по keepalive, которая объясняет это гораздо более подробно.

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO

Так как Java не позволяет вам контролировать фактическое время keepalive, вы можете использовать примеры для их изменения, если вы используете ядро ​​Linux (или основанную на процессоре ОС).

Ответ 7

В JAVA Socket - TCP-соединения управляются на уровне ОС, java.net.Socket не предоставляет встроенной функции для установки тайм-аутов для пакета keepalive на уровне для каждого сокета. Но мы можем включить опцию keepalive для java-сокета, но по умолчанию для обработки после устаревших подключений tcp требуется 2 часа 11 минут (7200 секунд). Это соединение будет доступно в течение очень долгого времени перед продувкой. Поэтому мы нашли некоторое решение для использования Java Native Interface (JNI), которые вызывают собственный код (c++) для настройки этих параметров.

**** Windows OS ****

В операционной системе Windows keepalive_time & keepalive_intvl можно настраивать, но tcp_keepalive_probes не может быть изменена. По умолчанию, когда инициализируется сокет TCP, устанавливается тайм-аут keep-alive на 2 часа, а интервал сохранения - 1 секунда. Системное значение по умолчанию для тайм-аута keep-alive можно контролировать с помощью параметра реестра KeepAliveTime, который принимает значение в миллисекундах.

В Windows Vista и более поздних версиях число хранимых зондов (повторных передач данных) установлено в 10 и не может быть изменено.

В Windows Server 2003, Windows XP и Windows 2000 настройка по умолчанию для числа зондов keep-alive составляет 5. Количество зондов keep-alive контролируется. Для Windows Winsock библиотека IOCTLs используется для настройки параметров tcp-keepalive.

int WSAIoctl (SocketFD,//дескриптор, идентифицирующий сокет SIO_KEEPALIVE_VALS,//dwIoControlCode (LPVOID) lpvInBuffer,//указатель на tcp_keepalive struct (DWORD) cbInBuffer,//длина входного буфера NULL,//выходной буфер 0,//размер выходной буфер (LPDWORD) lpcbBytesReturned,//количество возвращенных байтов NULL,//OVERLAPPED структура NULL//процедура завершения);

ОС Linux

У Linux есть встроенная поддержка keepalive, которая должна быть включена в сети TCP/IP для ее использования. Программы должны запрашивать контроль keepalive для своих сокетов, используя интерфейс setsockopt.

int setsockopt (int socket, int level, int optname, const void * optval, socklen_t optlen)

Каждый клиентский сокет будет создан с использованием java.net.Socket. Идентификатор дескриптора файла для каждого сокета будет извлекаться с использованием java-отражения.

Ответ 8

Для Windows в соответствии с документами Microsoft

  • KeepAliveTime (REG_DWORD, миллисекунды, по умолчанию не установлен, что означает 7 200 000 000 = 2 часа) - аналог tcp_keepalive_time
  • KeepAliveInterval (REG_DWORD, миллисекунды, по умолчанию не установлено, что означает 1000 = 1 секунду) - аналог tcp_keepalive_intvl
  • Поскольку Windows Vista не имеет аналогов для tcp_keepalive_probes, значение фиксировано на 10 и не может быть изменено