自分メモ兼情報緩募なブログエントリです。

SSH でサーバーにリモートログインして作業している途中で通信が途切れてしまう(プロセスが死んでしまうわけではなく、通信が切れてしまう)ケースがあります。自分が比較的頻度高くやっちゃうのは、電車内からテザリングを使ってリモートログインした先で Node.js のサーバーを動かしていて、地下鉄に入って通信が遮断しちゃうケースです。

これをやってしまって困るのは、例えば Node.js のサーバーを 8000 番ポートで動かしていたとすると、8000 番ポートへの listen が生きたままの状態で通信が切れてしまうことです。繋がっていれば Ctrl+C でサーバーを落とすことができるのですが、繋がっていないので Ctrl+C を入力する端末がありません。ということは再度リモートログインしてプログラムを修正して再度実行・・・しようとしても「そのポートは使われています」エラーになってしまいます。なんとかして元のプロセスを止めなければなりません。


※余談ですが、本来はこうならないように(途中で通信が切れてしまうことを想定して) screentmux などの端末のマルチプレクサーを使って作業するべきです。ただ今回はマルチプレクサーを使っていない時にこうなってしまった場合の対処方法についての話です。


以下で紹介する方法が正解かどうかはわからないのですが、自分の対処方法を紹介します。考え方としては「プロセスが残っているはずの SSH を探し出して息の根を止める」というアプローチです。

というわけで、まずは再度リモートログインした先で ps コマンドを実行して、自分が所有しているプロセスを一覧表示します(ちなみに実行コマンド内で `whoami` を実行していますが、自分の環境だとこの結果は dotnsf となり、dotnsf という文字を含むプロセスの一覧を表示しています):
$ ps -aux | grep `whoami`

root      4335  0.0  0.0  94924  7092 ?        Ss   08:19   0:00 sshd: dotnsf [priv]
dotnsf    4410  0.0  0.0  94924  4428 ?        S    08:20   0:00 sshd: dotnsf@pts/8
dotnsf    4411  0.0  0.0  23912  5620 pts/8    Ss   08:20   0:00 -bash
dotnsf    4654  0.0  0.5 935364 41736 pts/8    Sl+  08:37   0:00 node app
root      5167  0.0  0.0  94924  6964 ?        Ss   09:20   0:00 sshd: dotnsf [priv]
dotnsf    5243  0.0  0.0  94924  3408 ?        S    09:20   0:00 sshd: dotnsf@pts/9
dotnsf    5244  0.1  0.0  23800  5392 pts/9    Ss   09:20   0:00 -bash
dotnsf    5270  0.0  0.0  38376  3392 pts/9    R+   09:21   0:00 ps -aux
dotnsf    5271  0.0  0.0  15256  1012 pts/9    S+   09:21   0:00 grep --color=auto dotnsf
dotnsf   23891  0.9  1.4 1661748 118288 ?      Sl    2月23 651:40 /opt/couchdb/bin/../erts-7.3/bin/beam.smp -K true -A 16 -Bd -- -root /opt/couchdb/bin/.. -progname couchdb -- -home /opt/couchdb -- -boot /opt/couchdb/bin/../releases/2.0.0/couchdb -kernel inet_dist_listen_min 9100 -kernel inet_dist_listen_max 9100 -kernel error_logger silent -sasl sasl_error_logger false -noshell -noinput -config /opt/couchdb/bin/../releases/2.0.0/sys.config
dotnsf   23940  0.0  0.0   4512   856 ?        Ss    2月23   0:00 sh -s disksup
dotnsf   23941  0.0  0.0   4232    72 ?        Ss    2月23   0:05 /opt/couchdb/bin/../lib/os_mon-2.4/priv/bin/memsup
dotnsf   23942  0.0  0.0   4364    76 ?        Ss    2月23   0:00 /opt/couchdb/bin/../lib/os_mon-2.4/priv/bin/cpu_sup
dotnsf   26173  0.0  0.0  45276  3140 ?        Ss    2月15   0:00 /lib/systemd/systemd --user
dotnsf   26174  0.0  0.0 210940  2152 ?        S     2月15   0:00 (sd-pam)
dotnsf   31713  0.0  0.0  11140   312 ?        Ss    3月30   0:00 ssh-agent
  (↑青字が実行コマンドです)


結果の中で注目すべきは赤字にした2行です。dotnsf が sshd から pts(仮想端末)を使っているプロセスが(左から2列目の数値でいうと) 4410 と 5243 の2つあります(実際にコマンドを実行した結果は3つ以上みつかるかもしれません)。この2つのうち、どちらかは今自分がリモートログインに使っている仮想端末のプロセスで、もう1つは今回のターゲットとなる行方不明のプロセスです。このどちらか正しい方のプロセスを kill することで目的を達成することができます。

というわけで、「どちらかは正解、間違えると自分が死ぬ」という下図のような状況なわけです(笑):
jigenbakudan_kaitai_shifuku




ここでの問題は「どちらが目的のプロセスかを判断する方法」なのですが、これって正解あるんでしょうか? (^^; 明確な方法があったら自分も知りたいです。

自分がやっている判断方法としては2つあります:
・時刻(左から9列目)を見る。どちらかは自分がログインしているプロセスということは、そのプロセスの時刻は自分がログインした時刻になっているので、自分が現在ログインしているプロセスをなんとなく判断できる。
・プロセス番号(この例だと 4410 と 5243)は大抵小さい方が古い。現在のログインに使っているプロセスの方が新しいはず。


で、この基準で考えるとプロセス番号 5243 の方が現在使っているプロセスに該当するので、もう1つの 4410 のプロセスが息の根を止めるべきプロセス、と判断できることになります。ただこの考え方は経験的なもので、もしかすると別の確実な方法があるかもしれません(誰か知っていたら教えてください)。


(↓追記)
who コマンドで自分が現在いる TTY を調べることができる、という指摘をいただきました。確かに使えそうです。
$ who
dotnsf   pts/8        2018-04-12 21:00 (192.168.X.X)

(↑追記)


というわけで、4410 を kill することにします:
$ kill 4410

まあ仮に間違えていたとしても自分が強制ログアウトされるだけなので、そしたらもう一度リモートログインしてもう1つの方を kill し直せばいいんですけどね。。

で、これで上手く元のプロセスを消すことができていれば、再度実行した時に「そのポートは使われています。。」エラーは消える、はず。