Dlaczego konsole czasami zawieszają się na zawsze po zerwaniu połączenia SSH?

89

Widziałem to z tyloma konsolami (na Linuksie, Macu ...) i wieloma różnymi maszynami w wielu różnych sieciach. Nigdy nie potrafię wskazać dokładnego powodu, dla którego tak się dzieje: Wszystko, co musisz zrobić, to zalogować się na maszynie przez SSH. Jeśli połączenie z jakiegoś powodu zostanie zerwane (dla uproszczenia, powiedzmy, że kabel sieciowy został wyciągnięty), to czasami konsola po prostu zawiesza się na zawsze - innym razem po prostu dobrze wychodzi z powłoki macierzystej.

To takie denerwujące, gdy tak się dzieje (np. Tracisz historię poleceń). Czy może istnieje tajny skrót klawiaturowy, który może wymusić wyjście (Ctrl-C lub Ctrl-D nie działają)? A jaki jest powód tego losowego „błędu” we wszystkich implementacjach?

Chris Lercher
źródło
W tym wątku wydaje się właściwe wspomnienie Mosh (Mobile Shell), który dobrze radzi sobie z awariami połączeń, w tym z roamingiem (zmiana adresu IP) i innymi rzeczami.
Ciprian Tomoiagă

Odpowiedzi:

137

Istnieje „tajny” skrót klawiaturowy, który wymusza wyjście: ~) Z zamrożonej sesji naciśnij kolejno następujące klawisze: Enter~.Tylda (tylko po nowej linii) jest rozpoznawana przez klienta ssh jako sekwencja ucieczki, a kropka informuje klient, aby zakończyć działalność bez zbędnych ceregieli.

Długie zawieszanie się w kwestiach komunikacyjnych nie jest błędem, sesja SSH spotyka się w nadziei, że druga strona wróci. Jeśli sieć się zepsuje, czasem nawet kilka dni później możesz odzyskać sesję SSH. Oczywiście możesz wyraźnie powiedzieć, żeby się poddał i umarł w powyższej sekwencji. Istnieją również różne rzeczy, które możesz zrobić, takie jak ustawianie limitów czasu podtrzymania w kliencie, aby jeśli nie miał aktywnego łącza przez określony czas, wyłącza się sam, ale domyślnym zachowaniem jest zachowanie podłączony jak to możliwe!

Edycja: Innym przydatnym zastosowaniem tego klucza przerwania jest zwrócenie uwagi lokalnego klienta ssh i uruchomienie go w tle, aby powrócił na chwilę do lokalnej powłoki - powiedzmy coś z historii - a następnie przygotuj go, aby działał zdalnie. Enter~ Ctrl+, Zaby wysłać klienta ssh do kolejki zadań w tle lokalnej powłoki, a następnie fgjak zwykle, aby go odzyskać.

Edycja: Podczas pracy z zagnieżdżonymi sesjami SSH możesz dodać wiele znaków tyldy, aby wyjść tylko z jednej sesji SSH w łańcuchu, ale zachować pozostałe. Na przykład, jeśli jesteś zagnieżdżony na 3 poziomach (tj. Ssh z local-> Machine1-> Machine2-> Machine3), Enter~.wróci do lokalnej sesji, Enter~~.opuści cię na komputerze Machine1 i Enter~~~.pozostawi cię na komputerze Machine2 . Działa to również w przypadku innych sekwencji ucieczki, takich jak tymczasowe przeniesienie sesji ssh na tło. Powyższe działa na każdym poziomie zagnieżdżenia, po prostu dodając więcej tyldy.

Na koniec możesz użyć Enter~?do wydrukowania menu pomocy dostępnych poleceń ucieczki.

TL; DR - obsługiwane komendy specjalne to Obsługiwane sekwencje specjalne:

 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)
Caleb
źródło
11
+1 za znajomość hasła probekta tajnego dodekatouple do strzelania sshd w głowę. Czy dowiedziałeś się o tym w ten sam sposób, co ja (błędne pisanie ~/.somethingorotherpo naciśnięciu klawisza Enter)?
voretaq7
2
@ voretaq7: Nie, nie byłem taki bystry, ale kiedy ktoś mnie oszukał, powiedziałem: „Naprawdę? Więc to się działo przez te wszystkie czasy, kiedy moja skorupa po prostu BANG! bez żadnego powodu, kiedy pisałam?” . To nie jest powszechna sekwencja, z wyjątkiem pomyłek tej, o której wspominasz, ale może się zdarzyć.
Caleb
14
Przy czym „sekret” oznacza „na stronie podręcznika”.
larsks
4
Chociaż wiele osób nie wie o tym, jest to naprawdę tajemnica na pierwszy rzut oka. man sshobejmuje to w ESCAPE CHARACTERSsekcji. ~.(Disconnect) i ~^Z(background ssh) są bardzo przydatne.
Stefan Lasiewski
9
Oczywiście, że jest na stronie podręcznika man :) Użyłem tylko słowa „sekret”, ponieważ OP działało, i używałem języka w policzek. Problem z tą funkcją polega na tym, że ludzie nie wiedzą, gdzie jej szukać, oczekują, że znaki kontrolne i takie sygnały będą częścią powłoki. Gdy wiesz, gdzie szukać, a nawet o co pytać, oczywiście, że tam jest.
Caleb
12

SSH oferuje możliwość utrzymania przy życiu. Dodaj następujące elementy do lokalnego ~/.ssh/config(stwórz, jeśli nie istnieje):

ServerAliveInterval 15
ServerAliveCount 3

To ustawienie ustanowi sygnał podtrzymywania wysyłany co 15 sekund przez bezpieczny tunel. Po trzech kolejnych awariach klient SSH zakończy działanie.

Zauważ, że w niektórych systemach (w tym macOS 10.14) zamiast tego musi to być:

ServerAliveInterval 15
ServerAliveCountMax 3

Zaczerpnięte z tej odpowiedzi na ask.ubuntu: https://askubuntu.com/a/29967/30266

krlmlr
źródło
9

To, że się zawiesza, jest funkcją TCP, a nie SSH. Aplikacja nie może wiedzieć, że sesja / połączenie TCP zostało przerwane, chyba że TCP poinformuje aplikację korzystającą z połączenia, że ​​połączenie już nie istnieje. Z perspektywy każdego hosta sesja TCP jest nadal w stanie Ustanowiony i nic nie znaczy, że długa sesja bezczynności (brak przepływu danych) nie jest ważna poza RST lub brakiem odpowiedzi na pakiet podtrzymujący TCP (który nie jest powszechnie wdrażany). Wydaje mi się, że to nie jest błąd w SSH. Spodziewałbym się takiego zachowania.

joeqwerty
źródło
5

Jeśli połączenie zostanie poprawnie zawieszone, żadne magiczne naciśnięcie klawisza nie przejdzie, ponieważ połączenie jest już zawieszone przed wydaniem naciśnięcia klawisza. Możesz nakazać klientowi zakończenie pracy, ale nie wpłynie to na historię przechowywaną (lub nie) na końcu serwera.

Chociaż tak naprawdę nie odpowiada to na pytanie, może pomóc w zmniejszeniu skutków zawieszenia połączenia: kiedy pracuję zdalnie (a nawet zwykle, gdy nie jestem), biegam screen(z byobuopakowaniem lub bez niego, w zależności od jego dostępności) więc jeśli nastąpi jakikolwiek spadek połączenia, moja sesja z całą swoją historią zostanie zachowana i dostępna w stanie, w którym ją opuściłem po ponownym połączeniu.

David Spillett
źródło
6
Twoje sugestie dotyczące ekranu są w porządku, ale pierwszy bit w rzeczywistości nie dotyczy problemu. Nie musisz przenosić kluczy do odległej strony, musisz tylko przekazać je do LOKALNEGO klienta ssh! OP chce odzyskać swoją lokalną powłokę, w tym historię. SSH przejmuje je i nie reaguje na normalne sekwencje przerwania, takie jak CTRL-C, ponieważ przekazuje je dalej. Jest sposób na przejście i zakończenie klienta lokalnego, zobacz moją odpowiedź. Historia na lokalnym końcu zazwyczaj jest przechowywana, jeśli zalogujesz się ponownie, w zależności od konfiguracji powłoki.
Caleb
2
@Caleb: pytanie konkretnie wspomniało o utracie historii, a historia poleceń jest przechowywana po stronie serwera. Aby powiedzieć serwerowi, aby zrobił coś innego z historią, musisz otrzymać wiadomość do serwera, aby powiedział coś innego z historią. Oczywiście istnieją sposoby, aby bash (i niektóre inne powłoki) natychmiast zapisywał wiersze historii, zamiast zbierać je w pamięci RAM, dopóki użytkownik nie będzie poprawnie istniał powłoki z exit/, logoutktóra rozwiązałaby problem historii bez użycia screen.
David Spillett