SSHの接続断タイミング

SSH Frequently Asked Questions

SSHサーバがクライアントからの接続を切断するのは、クライアントからの接続により起動されたSSHプロセスがexitしてpipeを閉じることで、SSHサーバ(sshd)がそのSSHプロセスのstdout/stderrに繋がるpipeでend-of-file(eof)を確認したとき。

この挙動は、以下のようなコマンド(catがfoo.txtの全てのデータを読みだした後すぐにssh接続は切断される)で、SSHプロセスが全てのデータを読み出す前にsshdがその接続を閉じてしまい、データの最後の部分が欠損するというRace condition*1が存在することが確認されたために、採用された。

$ ssh server cat foo.txt

しかし、そのSSHプロセスがバックグラウンドで処理を継続する子プロセスを起動していたとき、子プロセスは全てのpipeを親プロセスから受け継ぐため、SSHプロセスがexitしてもSSHサーバはeofを見ることがなく、その接続を閉じる機会を失う。

そのため、バックグラウンドで処理を継続したい場合は、以下のように子プロセスのpipeはリダイレクトしておかなくてはいけない。(標準入力もバックグラウンドプロセスに必要無い)

$ xterm < /dev/null >& /dev/null &

  • Cシェル系でstdout/stderrをまとめてリダイレクトしたい場合は>&でよい
  • Bシェルでの2>&1が暗黙に行われている

*1:子プロセスによりwriteシステムコールが実行されてデータがpipeに書き出され、データはsshdによって読み出されるのを待っているが、スケジューリングの結果として子プロセスのexitがそれよりも前にsshdに通知されてしまうため、データが読み出されるよりも前にsshdが終了してしまう