Kiedy jest wymagana opcja TCP SO LINGER (0)?

Myślę, że rozumiem formalne znaczenie opcji. W niektórych starszych kodzie, które teraz obsługuję, opcja jest używana. Klient skarży się na RST jako odpowiedź na FIN z jego strony na połączenie blisko z jego strony.

Nie jestem pewien, czy mogę go bezpiecznie usunąć, ponieważ nie rozumiem, kiedy powinien być używany.

Czy możesz podać przykład, kiedy opcja będzie wymagana?

Author: jww, 2010-09-21

7 answers

Typowym powodem ustawiania limitu czasu SO_LINGER Na zero jest unikanie dużej liczby połączeń znajdujących się w stanie TIME_WAIT, wiążących wszystkie dostępne zasoby na serwerze.

Gdy połączenie TCP jest zamknięte czysto, koniec, który zainicjował zamknięcie ("aktywne zamknięcie") kończy się połączeniem znajdującym się w TIME_WAIT przez kilka minut. Jeśli więc twój protokół jest taki, w którym Serwer inicjuje zamknięcie połączenia i obejmuje bardzo dużą liczbę krótkotrwałych połączeń, to może być podatny na ten problem.

To nie jest dobry pomysł - TIME_WAIT istnieje nie bez powodu (aby zabłąkane pakiety ze starych połączeń nie kolidowały z nowymi połączeniami). Lepszym pomysłem jest przeprojektowanie protokołu na taki, w którym Klient inicjuje zamknięcie połączenia, jeśli to możliwe.

 85
Author: caf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-30 11:18:46

Dla mojej sugestii, proszę przeczytać ostatni rozdział: "Kiedy używać SO_LINGER z timeout 0" .

Zanim przejdziemy do tego mały wykład o:

  • zwykłe zakończenie TCP
  • TIME_WAIT
  • FIN, ACK oraz RST

Zwykłe zakończenie TCP

Normalna Sekwencja zakończenia TCP wygląda tak (uproszczone):

Mamy dwóch rówieśników: A i B

  1. a calls close()
    • A wysyła FIN do B
    • A przechodzi w FIN_WAIT_1 Stan
  2. B otrzymuje FIN
    • B wysyła ACK do a
    • B przechodzi w CLOSE_WAIT Stan
  3. A otrzymuje ACK
    • A przechodzi w FIN_WAIT_2 Stan
  4. B wywołania close()
    • B wysyła FIN do a
    • B przechodzi w LAST_ACK Stan
  5. A otrzymuje FIN
    • A wysyła ACK do B
    • A przechodzi w TIME_WAIT Stan
  6. B otrzymuje ACK
    • B przechodzi do CLOSED stanu-tzn. jest usuwany z tabel gniazd

TIME_WAIT

Więc peer, który inicjuje zakończenie-tzn. pierwsze wywołanie close() - skończy w stanie TIME_WAIT.

Aby zrozumieć, dlaczego stan TIME_WAIT jest naszym przyjacielem, przeczytaj sekcję 2.7 w" UNIX Network Programming " third edition autorstwa Stevens et al (strona 43).

Jednak może to być problem z dużą ilością gniazd w stanie TIME_WAIT Na serwerze, ponieważ może w końcu uniemożliwić przyjmowanie nowych połączeń.

Aby obejść ten problem, widziałem wiele sugestii, aby ustawić opcję so_linger socket z timeout 0 przed wywołaniem close(). Jest to jednak złe rozwiązanie, ponieważ powoduje zakończenie połączenia TCP z błędem.

Zamiast tego Zaprojektuj protokół aplikacji tak, aby zakończenie połączenia było zawsze inicjowane od strony klienta. Jeśli klient zawsze wie, kiedy odczytał wszystkie pozostałe dane, może rozpocząć sekwencję terminacji. Jako przykład, przeglądarka wie z nagłówka HTTP Content-Length, kiedy odczytuje wszystkie dane i może zainicjować zamknięcie. (Wiem, że w HTTP 1.1 utrzyma go przez jakiś czas w celu ewentualnego ponownego użycia, a następnie go zamknie.)

Jeśli serwer musi zamknąć połączenie, Zaprojektuj protokół aplikacji tak, aby serwer poprosił Klienta o wywołanie close().

Kiedy używać SO_LINGER z timeout 0

Ponownie, zgodnie z "UNIX Network Programming" trzeci wydanie strony 202-203, ustawienie {[27] } Z timeout 0 przed wywołaniem close()spowoduje zainicjowanie normalnej sekwencji zakończenia , a nie.

Zamiast tego, peer ustawienie tej opcji i wywołanie close() wyśle RST (Reset połączenia), który wskazuje na warunek błędu i tak będzie postrzegany na drugim końcu. Zazwyczaj zobaczysz błędy, takie jak "reset połączenia przez peera".

Dlatego w normalnej sytuacji jest to naprawdę zły pomysł, aby ustawić]} z timeoutem 0 przed wywołaniem close() - od teraz wywołane – w aplikacji serwerowej. Jednak pewna sytuacja i tak tego wymaga:]}
  • jeśli klient Twojej aplikacji serwerowej źle się zachowuje (times out, zwraca nieprawidłowe dane, itd.) aborcyjne zamknięcie ma sens, aby uniknąć utknięcia w CLOSE_WAIT lub zakończenia w stanie TIME_WAIT.
  • jeśli musisz ponownie uruchomić aplikację serwerową, która obecnie ma tysiące połączeń z klientami możesz rozważyć ustawienie tej opcji gniazda, aby uniknąć tysięcy gniazd serwera w TIME_WAIT (podczas wywoływania close() z końca serwera), ponieważ może to uniemożliwić serwerowi uzyskanie dostępnych portów dla nowych połączeń klienckich po ponownym uruchomieniu.
  • na stronie 202 we wspomnianej książce jest wyraźnie napisane: "istnieją pewne okoliczności, które uzasadniają użycie tej funkcji do wysłania aborcyjnego zamknięcia. Jednym z przykładów jest serwer terminali RS - 232, który może wisieć na zawsze w CLOSE_WAIT, próbując dostarczy dane do zablokowanego portu terminala, ale odpowiednio zresetuje zablokowany port, Jeśli otrzyma RST, aby odrzucić oczekujące dane."

Polecam ten długi artykuł, który moim zdaniem daje bardzo dobrą odpowiedź na twoje pytanie.

 195
Author: mgd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-26 14:29:46

Gdy linger jest włączony, ale timeout wynosi zero, stos TCP nie czeka na wysłanie oczekujących danych przed zamknięciem połączenia. Dane mogą zostać utracone z tego powodu, ale ustawiając linger w ten sposób, akceptujesz to i prosisz, aby połączenie zostało natychmiast zresetowane, a nie zamknięte z wdziękiem. Powoduje to wysłanie RST zamiast zwykłej płetwy.

Dzięki EJP za komentarz, Zobacz TUTAJ Po szczegóły.

 17
Author: Len Holgate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-24 09:01:47

To, czy można bezpiecznie usunąć linger w kodzie, zależy od typu aplikacji: czy jest to "klient" (otwarcie połączeń TCP i aktywne zamknięcie go w pierwszej kolejności) czy "serwer" (nasłuchiwanie otwarcia TCP i zamknięcie go po zainicjowaniu zamknięcia przez drugą stronę)?

Jeśli Twoja aplikacja ma charakter "klienta" (najpierw zamykasz) i inicjujesz i zamykasz ogromną liczbę połączeń z różnymi serwerami (np. gdy Twoja aplikacja jest aplikacją monitorującą nadzorującą osiągalność ogromnej liczby różnych serwerów) Twoja aplikacja ma problem, że wszystkie połączenia klienckie utknęły w stanie TIME_WAIT. Następnie polecam skrócić timeout do mniejszej wartości niż domyślna, aby nadal zamykać wdzięcznie, ale zwolnić zasoby połączeń klienta wcześniej. Nie ustawiłbym timeoutu na 0, ponieważ 0 nie wyłącza się z Finem, ale przerywa z RST.

Jeśli Twoja aplikacja ma smak "klienta" i musi pobrać ogromną ilość w przypadku małych plików z tego samego serwera, nie należy inicjować nowego połączenia TCP dla każdego pliku i kończy się w ogromnej ilości połączeń klienckich w TIME_WAIT, ale zachować połączenie otwarte i pobrać wszystkie dane przez to samo połączenie. Opcja Linger może i powinna zostać usunięta.

Jeśli Twoja aplikacja jest "serwerem" (close second as reaction to peer ' s close), po close() Twoje połączenie jest zamykane z wdziękiem, a zasoby są zwalniane, ponieważ nie wprowadzasz stanu TIME_WAIT. Nie należy stosować leku Linger. Ale jeśli Twoja aplikacja sever ma proces nadzorczy wykrywający nieaktywne otwarte połączenia bezczynne przez długi czas (należy zdefiniować "długi"), możesz zamknąć to nieaktywne połączenie z boku - zobacz to jako rodzaj obsługi błędów - z przerwanym zamknięciem. Odbywa się to poprzez ustawienie limitu czasu linger na 0. close() wyśle następnie RST do klienta, mówiąc mu, że jesteś zły: -)

 6
Author: Grandswiss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-11 09:16:55

W serwerach możesz chcieć wysłać RST zamiast FIN podczas odłączania źle zachowujących się klientów. To pomija FIN-WAIT, a następnie TIME-WAIT Stany gniazd w serwerze, co zapobiega wyczerpywaniu zasobów serwera, a tym samym chroni przed tego rodzaju atakiem typu denial-of-service.

 1
Author: Maxim Egorushkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-19 16:52:40

Podoba mi się spostrzeżenie Maxima, że ataki DOS mogą wyczerpywać zasoby serwera. Dzieje się to również bez rzeczywiście złośliwego przeciwnika.

Niektóre serwery muszą radzić sobie z "niezamierzonym atakiem DOS", który występuje, gdy aplikacja kliencka ma błąd z wyciekiem połączenia, gdzie wciąż tworzą nowe połączenie dla każdego nowego polecenia, które wysyłają na serwer. A potem być może w końcu zamykają swoje połączenia, jeśli uderzą w Ciśnienie GC, a może połączenia w końcu się skończą.

Innym scenariuszem jest scenariusz "wszyscy klienci mają ten sam adres TCP". Wtedy połączenia klienckie są rozróżniane tylko po numerach portów (jeśli łączą się z jednym serwerem). A jeśli klienci zaczną szybko uruchamiać otwieranie / zamykanie połączeń z dowolnego powodu, mogą wyczerpać przestrzeń krotki (addr klienta+port, IP serwera+port).

Więc myślę, że serwery mogą być najlepiej zalecane, aby przełączyć się na strategię Linger-Zero, gdy widzą dużą liczbę gniazd w stanie TIME_WAIT - chociaż nie naprawia zachowań klientów, może zmniejszyć wpływ.

 1
Author: Tim Lovell-Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-13 23:30:43

Gniazdo listen na serwerze może używać linger z czasem 0, aby mieć natychmiastowy dostęp do połączenia z powrotem do gniazda i zresetować wszystkich klientów, których połączenia nie zostały jeszcze zakończone. TIME_WAIT jest czymś, co jest interesujące tylko wtedy, gdy masz sieć wielościeżkową i może skończyć się źle zamówionymi pakietami lub w inny sposób masz do czynienia z dziwnym zamawianiem pakietów sieciowych/czasem przybycia.

 0
Author: Gregg Wonderly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-28 23:57:03