Czy połączenie za pomocą gniazda TCP „utrzymuje przy życiu”?

84

Słyszałem o utrzymywaniu aktywności HTTP, ale na razie chcę otworzyć połączenie przez gniazdo ze zdalnym serwerem.
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?

Kevin Boyd
źródło
1
Aby upewnić się, że „http keepalive” zazwyczaj nie jest związane z utrzymywaniem aktywności gniazda, mówi o funkcji HTTP / 1.1 polegającej na utrzymywaniu otwartych połączeń dla dalszych żądań. Jest to związane tylko z utrzymywaniem aktywności TCP, ponieważ musi wykrywać zerwane połączenia TCP (lub zwykle utrzymuje otwarte gniazda tylko przez ograniczony czas).
eckes

Odpowiedzi:

71

Gniazda TCP pozostają otwarte, dopóki nie zostaną zamknięte.

To powiedziawszy, bardzo trudno jest wykryć zerwane połączenie (zerwane, jak w przypadku routera, itp., W przeciwieństwie do zamkniętego) bez faktycznego wysyłania danych, więc większość aplikacji co jakiś czas wykonuje jakąś reakcję ping / pong, aby się upewnić połączenie jest nadal żywe.

Matthew Scharley
źródło
4
To dobry pomysł. Nie musisz , ale jeśli tego nie zrobisz, możesz nie wykryć zepsutego łącza, dopóki ktoś nie będzie chciał coś zrobić. Co może być dobre, ale nie musi (lub może, ale nie musi), w zależności od tego, co faktycznie próbujesz osiągnąć.
Matthew Scharley
1
@Pacerier: Zależy od protokołu, ponieważ jest całkowicie zależny od protokołu, ale w przypadku protokołów tekstowych, które wymagają jednego dosłownego polecenia „PING” i „PONG”, są dość typowe.
Matthew Scharley,
4
@MatthewScharley: Ten „ping pong” jest już zaimplementowany w naszej standardowej implementacji TCP i nazywa się „utrzymywanie przy życiu” (zobacz inną popularną odpowiedź na to pytanie). Czy jest jakiś powód, aby zaimplementować to na poziomie aplikacji?
Tim Cooper
7
@TimCooper: Tak naprawdę nie jest. Jak podkreśliłem w komentarzach do innych odpowiedzi, implementacja TCP nie jest przydatna w przypadku większości wymagań na poziomie aplikacji . Nie można wysłać jednego na żądanie, a dla większości systemów operacyjnych limit czasu podtrzymania aktywności TCP można skonfigurować tylko na poziomie całego systemu i ustawić zbyt wysoko, aby był ogólnie przydatny dla aplikacji.
Matthew Scharley
14
@Tim Powodem utrzymywania aktywności na poziomie aplikacji jest to, że standard TCP zaleca ustawienie licznika czasu utrzymywania aktywności na więcej niż dwie godziny. Nigdy nie widziałem połączenia TCP bez ruchu, które przetrwało tym razem. W związku z tym elementy utrzymujące aktywność TCP są domyślnie bezużyteczne.
Robert
97

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 RSTpakiet, 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
    • domyślnie 7200 sekund
  • tcp_keepalive_probes
    • domyślny 9
  • tcp_keepalive_intvl
    • domyślnie 75 sekund

Proces przebiega następująco:

  1. Klient otwiera połączenie TCP
  2. Jeśli połączenie jest ciche przez tcp_keepalive_timekilka sekund, wyślij pojedynczy pusty ACKpakiet. 1
  3. Czy serwer odpowiedział ACKwłasnym odpowiednikiem?
    • Nie
      1. Poczekaj tcp_keepalive_intvlsekundy, a następnie wyślij kolejnąACK
      2. Powtarzaj, aż liczba ACKwysłanych sond będzie równa tcp_keepalive_probes.
      3. Jeśli w tym momencie nie otrzymano żadnej odpowiedzi, wyślij a RSTi 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 keepidlei keepintvlw milisekundach, w przeciwieństwie do Linuksa, który używa sekund.

Można ustawić właściwości, sysctlktó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 tcpaby uzyskać więcej informacji.

2. Ten pakiet jest często nazywany pakietem „Keep-Alive”, ale w specyfikacji TCP jest to zwykły ACKpakiet. 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 .

Cory Klein
źródło
Bardzo pomocne, dzięki! Jeden dodatek: w przypadku systemu Windows wymagane jest ponowne uruchomienie, aby nowe wartości KeepAliveTime były skuteczne.
geld0r
W systemie AIX można sprawdzić bieżące ustawienia funkcji TCP Keep-Alive za pomocą $ no -a | grep tcp_keepkomendy.
Jarek Przygódzki
56

Szukasz opcji gniazda SO_KEEPALIVE.

W Java Socket API eksponuje „keep-alive” do aplikacji za pośrednictwem setKeepAlivei getKeepAlivemetod.

EDYCJA: SO_KEEPALIVE jest zaimplementowana w stosach protokołów sieciowych systemu operacyjnego bez wysyłania żadnych „prawdziwych” danych. Interwał utrzymywania aktywności jest zależny od systemu operacyjnego i może być dostosowywany za pomocą parametru jądra.

Ponieważ żadne dane nie są wysyłane, SO_KEEPALIVE może tylko przetestować żywotność połączenia sieciowego, a nie usługi, z którą jest połączone gniazdo. Aby przetestować to drugie, musisz zaimplementować coś, co obejmuje wysyłanie wiadomości do serwera i uzyskiwanie odpowiedzi.

Stephen C.
źródło
4
Jeśli ustawię setKeepAlive (true); jaki byłby interwał? ... czy Java będzie również wysyłać komunikaty o podtrzymaniu aktywności w domyślnym interwale, czy będę musiał to robić programowo?
Kevin Boyd
3
unixguide.net/network/socketfaq/4.7.shtml Zawiera opis SO_KEEPALIVE. Nie chodzi o to, czego chciał OP, chociaż jest to opcja oparta na protokole w stosunku do tego, co zasugerowałem ... chociaż raz na dwie godziny nie zrobi wiele dla aplikacji.
Matthew Scharley
4
@MatthewScharley Jeśli chodzi o „ domyślnie nie może to być mniej niż dwie godziny”… oznacza, że ​​może to być mniej niż dwie godziny, prawda?
Pacerier,
1
@MatthewScharley - „Masz rację, ale to byłoby specyficzne dla implementacji ...” . Przerwa w utrzymywaniu życia, która nie może trwać krócej niż dwie godziny, byłaby tak bezużyteczna, że ​​trudno wyobrazić sobie, by ktokolwiek ją stosował.
Stephen C
2
@Daniel - alternatywą (w Javie) byłoby ręczne utrzymanie przy życiu, jak wspomniano powyżej oraz w innych odpowiedziach. Niezbyt ładne, ale może lepsze niż zmiana ustawień domyślnych w całym systemie operacyjnym, która może zepsuć usługi systemowe lub inne aplikacje.
Stephen C,
34

TCP keepalive i HTTP keepalive to bardzo różne koncepcje. W TCP utrzymanie aktywności to pakiet administracyjny wysyłany w celu wykrycia nieaktualnego połączenia. W HTTP utrzymanie aktywności oznacza trwały stan połączenia.

To pochodzi ze specyfikacji TCP,

Pakiety utrzymujące aktywność MUSZĄ być wysyłane tylko wtedy, gdy nie zostały odebrane żadne pakiety danych lub potwierdzenia dla połączenia w określonym przedziale czasu. Ten interwał MUSI być konfigurowalny i MUSI domyślnie wynosić nie mniej niż dwie godziny.

Jak widać, domyślny interwał utrzymywania aktywności TCP jest zbyt długi dla większości aplikacji. Może być konieczne dodanie funkcji keepalive w protokole aplikacji.

ZZ Coder
źródło
2
Możesz zmodyfikować interwał utrzymywania aktywności TCP, aby dopasować go do swojej aplikacji. Np msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei
@ZZCoder Czy możesz wyjaśnić, co to znaczy, kiedy mówisz „W HTTP utrzymanie aktywności oznacza stan trwałego połączenia”?
Pacerier,
1
@Pacerier: W HTTP/1.0każdym żądaniu / odpowiedzi konieczne było ponowne połączenie z serwerem. Ponieważ HTTP/1.1wprowadzili Keep-Alivenagłówek, który może być użyty do tego, aby serwer nie przerywał połączenia po zakończeniu przetwarzania odpowiedzi w celu ułatwienia żądania większej liczby plików i umożliwienia „pipeliningu”; wysyłanie wielu żądań, a następnie czekanie na powrót wszystkich danych.
Matthew Scharley,
Zasadniczo oznacza to, że wiele żądań HTTP będzie / powinno ponownie używać tego samego połączenia TCP (te połączenia mogą również mieć utrzymywanie aktywności, ale to nie mierzy do HTTP, więc jest to zasadniczo inna koncepcja).
Igor Čordaš
24

Jeśli jesteś za maskaradowym NATem (jak obecnie większość użytkowników domowych), istnieje ograniczona pula portów zewnętrznych, które muszą być współużytkowane przez połączenia TCP. Dlatego też NAT podszywający się pod maskę zakłada zwykle, że połączenie zostało zakończone, jeśli żadne dane nie zostały wysłane przez określony czas.

Ten i inne tego typu problemy (gdziekolwiek pomiędzy dwoma punktami końcowymi) mogą oznaczać, że połączenie nie będzie już „działać”, jeśli spróbujesz wysłać dane po rozsądnym okresie bezczynności. Jednak możesz nie odkryć tego, dopóki nie spróbujesz wysłać danych.

Korzystanie z funkcji utrzymywania aktywności zmniejsza ryzyko przerwania połączenia w jakimś miejscu na linii, a także pozwala szybciej dowiedzieć się o zerwanym połączeniu.

Artelius
źródło
Ach! dodasz tutaj dobrą uwagę, to znaczy musisz wziąć pod uwagę rzeczy pośrednie, które mogą utrudniać działanie połączenia, takie jak routery NAT itp.
Kevin Boyd
4
To dobra uwaga i dobre przypomnienie, że należy pamiętać o czymś więcej niż tylko o tym, co bezpośrednio wdrażamy. Również lemingi !!
Matthew Scharley
Zauważ, że współdzielenie plików p2p zarówno przeżuwa wiele portów, jak i generuje wiele połączeń zombie, co zwiększa prawdopodobieństwo, że NAT będzie musiał przyciąć nieaktywne połączenia.
Artelius
4
Niekoniecznie połączenie TCP jest identyfikowane przez 4 elementy: src ip, src port, dest ip, dest port. Możesz więc ponownie użyć tego samego portu zewnętrznego (źródłowego), o ile docelowy adres IP jest inny.
Dan Berindei,
1
O tak, masz rację. Myślę, że prawdziwym powodem jest to, że translatory NAT mają stałą tabelę otwartych połączeń ze względu na ograniczenia pamięci i czas wyszukiwania.
Artelius
4

Oto dodatkowa literatura na temat utrzymywania aktywności, która wyjaśnia to bardziej szczegółowo.

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

Ponieważ Java nie pozwala kontrolować rzeczywistych czasów utrzymywania aktywności, możesz użyć przykładów, aby je zmienić, jeśli używasz jądra Linuksa (lub systemu operacyjnego opartego na proc).

Jeach
źródło
1

W JAVA Socket - połączenia TCP są zarządzane na poziomie systemu operacyjnego, java.net.Socket nie udostępnia żadnej wbudowanej funkcji ustawiania limitów czasu dla pakietów utrzymywania aktywności na poziomie poszczególnych gniazd. Ale możemy włączyć opcję keepalive dla gniazda java, ale domyślnie zajmuje to 2 godziny 11 minut (7200 sekund) po nieaktualnych połączeniach tcp. To powoduje, że połączenie będzie dostępne przez bardzo długi czas przed czyszczeniem. Znaleźliśmy więc rozwiązanie umożliwiające użycie natywnego interfejsu Java (JNI), który wywołuje kod natywny (c ++) w celu skonfigurowania tych opcji.

**** System operacyjny Windows ****

W systemie operacyjnym Windows keepalive_time i keepalive_intvl mogą być konfigurowalne, ale tcp_keepalive_probes nie mogą być zmienione.Domyślnie, gdy gniazdo TCP jest zainicjowane, ustawia limit czasu utrzymywania aktywności na 2 godziny i interwał utrzymywania aktywności na 1 sekundę. Domyślną wartością limitu czasu utrzymania aktywności dla całego systemu można sterować za pomocą ustawienia rejestru KeepAliveTime, które przyjmuje wartość w milisekundach.

W systemie Windows Vista i nowszych liczba sond podtrzymujących aktywność (retransmisje danych) jest ustawiona na 10 i nie można jej zmienić.

W systemach Windows Server 2003, Windows XP i Windows 2000 domyślne ustawienie liczby sond utrzymujących aktywność to 5. Liczba sond utrzymujących aktywność jest kontrolowana. W systemie Windows biblioteka Winsock IOCTLs służy do konfigurowania parametrów tcp-keepalive.

int WSAIoctl (SocketFD, // deskryptor identyfikujący gniazdo SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // wskaźnik do tcp_keepalive struct (DWORD) cbInBuffer, // długość bufora wejściowego NULL, // bufor wyjściowy 0, // rozmiar bufor wyjściowy (LPDWORD) lpcbBytesReturned, // liczba zwróconych bajtów NULL, // struktura OVERLAPPED NULL // procedura uzupełniania);

System operacyjny Linux

Linux ma wbudowaną obsługę utrzymywania aktywności, która musi mieć włączoną obsługę sieci TCP / IP, aby z niej korzystać. Programy muszą żądać utrzymywania aktywności dla swoich gniazd za pomocą interfejsu setsockopt.

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

Każde gniazdo klienta zostanie utworzone za pomocą java.net.Socket. Identyfikator deskryptora pliku dla każdego gniazda zostanie pobrany przy użyciu odbicia java.

Suganya Vinayakam
źródło
0

Dla Windows zgodnie z Microsoft Docs

  • KeepAliveTime (REG_DWORD, milisekundy, domyślnie nie jest ustawione, co oznacza 7200000000 = 2 godziny) - analogicznie do tcp_keepalive_time
  • KeepAliveInterval (REG_DWORD, milisekundy, domyślnie nie jest ustawione, co oznacza 1000 = 1 sekunda) - analogicznie do tcp_keepalive_intvl
  • Ponieważ Windows Vista nie ma odpowiednika tcp_keepalive_probes, wartość jest ustalona na 10 i nie można jej zmienić
sperma
źródło