Czy to połączenie przez gniazdo pozostanie otwarte na zawsze, czy też jest z nim powiązany limit czasu podobny do utrzymywania aktywności HTTP?
Krótka odpowiedź brzmi: nie , nie pozostanie otwarte wiecznie, prawdopodobnie wyłączy się po kilku godzinach. Dlatego tak tam jest limit czasu i jest egzekwowane poprzez TCP keep-alive .
Jeśli chcesz skonfigurować limit czasu utrzymywania aktywności na swoim komputerze, zobacz sekcję „Zmiana limitów czasu TCP” poniżej. W przeciwnym razie przeczytaj resztę odpowiedzi, aby dowiedzieć się, jak działa TCP Keep-Alive.
Wprowadzenie
Połączenia TCP składają się z dwóch gniazd, po jednym na każdym końcu połączenia. Kiedy jedna strona chce zakończyć połączenie, wysyła RST
pakiet, który druga strona potwierdza i obie zamykają swoje gniazda.
Dopóki to jednak nie nastąpi, obie strony pozostaną otwarte na czas nieokreślony. To pozostawia otwartą możliwość, że jedna strona może zamknąć swoje gniazdo, celowo lub z powodu jakiegoś błędu, bez informowania drugiej strony za pośrednictwem RST
. Aby wykryć ten scenariusz i zamknąć przestarzałe połączenia, używany jest proces TCP Keep Alive.
Utrzymanie przy życiu procesu
Istnieją trzy konfigurowalne właściwości, które określają sposób działania Keep-Alives. W systemie Linux są to 1 :
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
Proces przebiega następująco:
- Klient otwiera połączenie TCP
- Jeśli połączenie jest ciche przez
tcp_keepalive_time
kilka sekund, wyślij pojedynczy pusty ACK
pakiet. 1
- Czy serwer odpowiedział
ACK
własnym odpowiednikiem?
- Nie
- Poczekaj
tcp_keepalive_intvl
sekundy, a następnie wyślij kolejnąACK
- Powtarzaj, aż liczba
ACK
wysłanych sond będzie równa tcp_keepalive_probes
.
- Jeśli w tym momencie nie otrzymano żadnej odpowiedzi, wyślij a
RST
i zakończ połączenie.
- Tak : wróć do kroku 2
Ten proces jest domyślnie włączony w większości systemów operacyjnych, dlatego martwe połączenia TCP są regularnie usuwane, gdy drugi koniec nie odpowiada przez 2 godziny i 11 minut (7200 sekund + 75 * 9 sekund).
Gotchas
Domyślnie 2 godziny
Ponieważ proces nie rozpoczyna się, dopóki połączenie nie jest domyślnie nieaktywne przez dwie godziny, nieaktualne połączenia TCP mogą utrzymywać się przez bardzo długi czas, zanim zostaną wyczyszczone. Może to być szczególnie szkodliwe w przypadku drogich połączeń, takich jak połączenia z bazą danych.
Utrzymywanie przy życiu jest opcjonalne
Zgodnie z RFC 1122 4.2.3.6 odpowiadanie na i / lub przekazywanie pakietów TCP Keep-Alive jest opcjonalne :
Implementatorzy MOGĄ włączyć „utrzymywanie przy życiu” do swoich implementacji TCP, chociaż praktyka ta nie jest powszechnie akceptowana. Jeśli włączone są funkcje utrzymywania aktywności, aplikacja MUSI mieć możliwość ich włączania lub wyłączania dla każdego połączenia TCP i MUSI one domyślnie być wyłączone.
...
Niezwykle ważne jest, aby pamiętać, że segmenty ACK, które nie zawierają żadnych danych, nie są niezawodnie przesyłane przez TCP.
Powodem jest to, że pakiety Keep-Alive nie zawierają żadnych danych i nie są bezwzględnie konieczne, a ich nadużywanie grozi zapychaniem tub w sieciach.
Jednak w praktyce z mojego doświadczenia wynika, że problem ten z czasem zmniejszył się, ponieważ przepustowość stała się tańsza; i dlatego pakiety Keep-Alive zwykle nie są odrzucane. Na przykład dokumentacja Amazon EC2 zawiera pośrednie poparcie dla Keep-Alive, więc jeśli hostujesz w AWS, prawdopodobnie możesz bezpiecznie polegać na Keep-Alive, ale Twój przebieg może się różnić.
Zmiana limitów czasu TCP
Na gniazdo
Niestety, ponieważ połączenia TCP są zarządzane na poziomie systemu operacyjnego, Java nie obsługuje konfigurowania limitów czasu na poziomie na gniazdo, na przykład w java.net.Socket
. Znalazłem kilka prób 3 wykorzystania natywnego interfejsu Java (JNI) do tworzenia gniazd Java, które wywołują kod natywny w celu skonfigurowania tych opcji, ale żadna z nich nie wydaje się mieć powszechnej akceptacji lub wsparcia społeczności.
Zamiast tego możesz zostać zmuszony do zastosowania swojej konfiguracji do systemu operacyjnego jako całości. Należy pamiętać, że ta konfiguracja wpłynie na wszystkie połączenia TCP uruchomione w całym systemie.
Linux
Aktualnie skonfigurowane ustawienia TCP Keep-Alive można znaleźć w
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
Możesz zaktualizować dowolne z nich w następujący sposób:
# 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
Takie zmiany nie będą się utrzymywać po ponownym uruchomieniu. Aby wprowadzić trwałe zmiany, użyj sysctl
:
sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Mac OS X
Aktualnie skonfigurowane ustawienia można wyświetlić za pomocą 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
Warto zauważyć, że Mac OS X definiuje keepidle
i keepintvl
w milisekundach, w przeciwieństwie do Linuksa, który używa sekund.
Można ustawić właściwości, sysctl
które będą zachowywać te ustawienia po ponownym uruchomieniu:
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
Alternatywnie możesz je dodać do /etc/sysctl.conf
(tworzenie pliku, jeśli nie istnieje).
$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3
Windows
Nie mam komputera z systemem Windows do potwierdzenia, ale odpowiednie ustawienia TCP Keep-Alive powinny znaleźć się w rejestrze pod adresem
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Przypisy
1. Zobacz, man tcp
aby uzyskać więcej informacji.
2. Ten pakiet jest często nazywany pakietem „Keep-Alive”, ale w specyfikacji TCP jest to zwykły ACK
pakiet. Aplikacje takie jak Wireshark są w stanie oznaczyć go jako pakiet „Keep-Alive” poprzez metaanalizę sekwencji i numerów potwierdzeń, które zawiera w odniesieniu do poprzedniej komunikacji w gnieździe.
3. Niektóre przykłady, które znalazłem z podstawowego wyszukiwania Google, to lucwilliams / JavaLinuxNet i flonatel / libdontdie .