0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

tmux は SSH 切断をどのように乗り越えるのか?

0
Posted at

はじめに

多くの計算機実験を行う学生が日常的に tmux を利用していることでしょう。

「とりあえず tmux 叩いとけば、SSHが切れても解析が止まらない」

その通りです。しかし、そのSSHを切断しても何故かプロセスを生存させている挙動が、どのようなロジックにより達成されるのか気になりませんか?

1. そもそも、SSH接続とはどういう状態なのか?

tmuxの話をする前に、まずは 「普通のSSH接続」 で何が起きているか、そしてなぜ 「回線が切れるとプロセスが死ぬのか」 を整理しましょう。ここが理解の出発点です。

sshdbash の親子関係

あなたが手元のPCから ssh user@server コマンドを叩いたとき、サーバー側では sshd (SSH Daemon) という常駐プロセスがあなたの接続を受け付けます。そして、この sshd があなた専用の子プロセス (例えば bash) を生成します。

sshdには「親」と「子」がいる
下図にある sshd は、正確にはあなたがログインした瞬間に fork された 「セッション用の子プロセス」 です。 1
サーバー内には常駐して接続を待ち受ける「親の sshd (Daemon)」もいますが、これはSSHを切断しても死にません。
今回問題になるのは、シェル (bash) の親となる「担当者の sshd」の方です。

09a8795e-1.png

SIGHUPシグナル

さて、研究が一息ついたのでPCをスリープし、PCのssh接続が途切れてしまったとします。この時、以下のようなプロセスが辿られます。

  1. 通信断絶: サーバー側の sshd は、あなたのPCからの応答がなくなったこと (またはTCP切断) を検知します。
  2. 親の死: sshd は「役割終了」と判断して自身のプロセスを閉じます。
  3. 子の巻き添え: ここでUNIX/Linuxの重要な仕様が発動します。端末 (この場合は sshd が提供していた接続) が切断されると、OSはそこぶら下がっていたセッションリーダー (bash) に対して、SIGHUP (Signal Hangup: 終了シグナル) を送信します。2
  4. 全滅: SIGHUP を受け取った bash は終了し、その子供である python プロセスも道連れに強制終了されます。

これが、我々が恐れる「SSH切断=計算プロセスの終了」のメカニズムです。

09a8795e-2.png


2. tmuxの介入

tmuxを起動すると、構造が劇的に変わります。ここで重要なのが、tmuxのクライアント・サーバー(C/S)モデルです。3

構造の分離

tmuxを起動すると、sshdbash の間に tmux Server が割り込みます。

7bd9eb63-3.png

切断時の挙動

Wi-Fiが切れたとき、死ぬのは sshd と、その直下にある tmux Client だけです。
tmux Serversshd とは親子関係にない (独立してバックグラウンドで動いている) ため、sshd が死んでも影響を受けません。これにより、ssh接続を切断しても計算プロセスを生存させることができます。

実際に確認してみる

tmuxを起動した状態とそうでない状態とで、プロセスツリーに差異があるかを確認してみましょう。

  • ssh接続した直後に実行
$ pstree -aps $$ 
systemd,1
  └─sshd,1501
      └─sshd,105887
          └─sshd,106038
              └─zsh,106041
                  └─pstree,106534 -aps 106041
  • tmuxを起動した状態で実行
$ pstree -aps $$
systemd,1
  └─tmux: server,106370
      └─zsh,106371
          └─pstree,106510 -aps 106371

この結果から、tmux server の親プロセスは sshd ではなく、systemd (PID: 1) になっていることがわかります。
tmuxが起動時に自身をバックグラウンドへ逃がしていることが確認できますね。

このおかげで、もし sshd が死んでも、親が違う tmux server は連鎖的なプロセス終了の対象から外れ、涼しい顔で生き残ることができます。


3. なぜ中のプロセスは「主人が消えた」ことに気づかないのか?

しかし、疑問が残ります。いくら tmux Server が生きていても、実際にユーザーからの入力を受け付けていた ssh が切れたなら、中の bash は「入力元がなくなった」と気づいてエラーになるはずではないでしょうか?

ここで登場するのが、PTY (Pseudo-Terminal / 疑似端末) という仕組みです。

MasterとSlave

PTYは MasterSlave のペアで構成される仮想デバイスです。

  • Slave側: 従来の物理端末と同じ振る舞いをします。bash はこれに接続され、「自分は端末に繋がっている」と信じ込みます。
  • Master側: ここを握っているプロセスが「端末の向こう側」として振る舞います。

通常のSSHでは sshd がMasterを握っていましたが、tmux環境下では tmux Server がMasterを握り続けます

tmux Server がMaster側をガッチリ掴んで離さない限り、OSは切断を検知しません。したがって、中の bash に死のシグナル (SIGHUP) が届くことは起きないわけですね。

7bd9eb63-4.png

実際に確認してみる

tty コマンドを叩いてみると、以下のような表示が確認できるはずです。

$ tty
/dev/pts/4

このように、仮想的なデバイスファイルが表示されます。

TTY (Teletypewriter) とは?
元々は「テレタイプ端末」という物理的な打鍵機を指す言葉でしたが、現在では 「文字を入出力するための標準的なインターフェース」 を指します。
Linuxの設計上、シェルは「相手が物理的な機械か (TTY) 、ソフトウェア的な仮想端末か (PTY) 」を区別しません。デバイスドライバがその差を吸収しているため、bashから見れば /dev/pts/4 も立派な「物理端末」のように見えているのです。 45

あなたが tmux セッション内でテキストを入力したとき、その文字は以下の経路をたどります。

  1. あなた のキーボード入力

  2. tmux client が受け取り、サーバーへ転送

  3. tmux server が Master側から書き込む

  4. Slave側 (/dev/pts/4) から bash がそれを読み込む

bash からすれば、端末デバイスファイルに対して read/write を行うだけで、相手が物理的なケーブルの先の人間なのか、tmux 経由なのかは区別がつきません。
このようにうまく shell を騙し、働かせ続けることができるわけです。

例外:SIGHUPが飛ぶケース
以下のケースでは、ロジック通り SIGHUP(またはプロセスの終了) が発生します。

  1. tmux自体を終了させた場合
    tmux kill-servertmux kill-session コマンドを実行したり、サーバー機自体を再起動した場合です。これらが起きると身代わり役の tmux Server プロセスが終了 するので、当然ながら握っていた「PTY Master」も閉じられ、POSIXの仕様通り OS は切断を検知し、中のプロセスに SIGHUP が送られます。
  2. シェル設定によるハングアップ
    稀なケースですが、シェルの設定(huponexit オプションなど)や、ログインスクリプト(logout hook)の記述によっては、セッション終了時に明示的にシグナルを送る挙動をする場合があります。

つまり、tmuxは「回線切れ」からは守ってくれますが、「サーバーダウン」や「意図的なプロセス終了」からは守れません。

まとめ

tmuxがSSH切断に強い理由は、黒魔術ではなく以下の3段階のロジックによるものです。

  1. 構造の分離:
    通信担当 (sshd / tmux Client) と、処理担当 (tmux Server) を別プロセスに分離
  2. 身代わり (Master):
    sshd の代わりに tmux Server が仮想端末の Master 側を握ることで、プロセスから「本当の切断」を隠蔽
  3. 仕様の回避:
    切断を検知させないことで、POSIX標準の SIGHUP (強制終了シグナル) の発生条件を回避

この記事を読んだ後 tmux で実験を回すことがあれば、裏で tmux Server が仮想のケーブル (PTY Master) を握りしめ、「まだ大丈夫だ」とシェルを騙し続けている姿を想像してあげてください。

参考文献
  1. sshd(8) — OpenBSD manual pages (DESCRIPTION, LOGIN PROCESS).

  2. General Terminal Interface (The Controlling Terminal, Modem Disconnect), The Open Group Base Specifications Issue 7 (POSIX.1-2017).

  3. Tony Narlock, The Tao of tmux, Leanpub. (Chapter 4: Server)

  4. pty(7) — Linux manual page, man7.org.

  5. tty(4) — Linux manual page, man7.org.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?