Syntax Error.

[Sy] Mac/Linuxでポートを使っているプロセスを調べるのに便利なlsofコマンド

2016/07/20

MacやLinuxで任意のポートを使っているプロセスを調べる 際に使える lsof コマンドについてです。使い方と lsof コマンドの仕組みについてちょっと掘り下げて調べてみました。元々はUnixのコマンドみたいですね。

試した環境

今回の動作確認は、CentOS6.5で行いました。このコマンドはMacでも同様に使えるので便利です。

lsof コマンドで指定ポートを使っているプロセスを調べる

このコマンドを理解するのはなかなか奥が深いですが、とりあえずこんな感じで指定したポートを使っているプロセスを調べることができます。

$ sudo lsof -i:80
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1311  root    6u  IPv4   8645      0t0  TCP *:http (LISTEN)
nginx   1314 nginx    6u  IPv4   8645      0t0  TCP *:http (LISTEN)

ポート番号の代わりにサービス名でもいけるので、ウェルノウンポートなどはこの方法も便利です。

$ sudo lsof -i:http
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1311  root    6u  IPv4   8645      0t0  TCP *:http (LISTEN)
nginx   1314 nginx    6u  IPv4   8645      0t0  TCP *:http (LISTEN)
ウェルノウンポートとは?

基本的にポート番号は設定次第でどうにでもできちゃいますが、慣習的に「このポート番号はこのサービスで使おう」というポートがあり、それらをウェルノウンポート(well-known port)と呼びます。例えば80番はhttp、443番はhttps、22番はssh、といった感じです。具体的には、0〜1023番ポートがウェルノウンポートとして予約されていて、root権限がないと勝手に使えなかったりします。

-Pオプションをさらにつけると、NAMEのところに表示されていたhttpといったサービス名がポート番号で表示されるようになります。

$ sudo lsof -i:80 -P
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1311  root    6u  IPv4   8645      0t0  TCP *:80 (LISTEN)
nginx   1314 nginx    6u  IPv4   8645      0t0  TCP *:80 (LISTEN)

ポートを使おうとしたら、既に使われてるというエラーが出たけど、どのプロセスが使ってるのか知りたい という場合に便利ですね。

本題のコマンドの説明は以上です。が、lsof についてもう少し知りたい方は続きをどうぞ!

(続きは少し難易度が高めになってます)

もうちょっと調べてみる

このコマンド、調べていくと何やら色々とややこしい話が出てきます。

lsof -hとすると help が見れますが、なんかよくわからないので、下記ページを見てみます。

⇒ lsof(8): open files - Linux man page

まず lsof というコマンド名は、 list open file からつけられているということがわかります。仮に lsof がポートを使っているプロセスを調べるためのコマンドだとすると、どうもしっくりこないですよね。

Description の最初には、こう書かれています。

Lsof revision N lists on its standard output file information about files opened by processes for the following UNIX dialects:

AIX 5.3
Apple Darwin 9 (Mac OS X 10.5)
FreeBSD 4.9 for x86-based systems
FreeBSD 7.[012] and 8.0 for AMD64-based systems
Linux 2.1.72 and above for x86-based systems
Solaris 9 and 10

「これらのUNIX系OSで使える、プロセスによって開かれたファイルの情報を標準出力に出すためのコマンドだよ」 って感じでしょうか。

なので、 lsof を使って「指定したポートを使っているプロセスを調べる」というのは、どちらかというとちょっと応用した使い方 だということなんだと言えると思います。

なんとなくですが、 ポートを使用する(listenする、とか言いますね)ためには、何かしら専用のファイルを開く必要があって、そのファイルをプロセスが開いているという情報が lsof で取得できる ので、結果として「指定したポートを使っているプロセスを調べる」ということができるのかな?とわかってきた気がします。

その確信を得るためには、Unix、Linuxのプロセスがポートを使う時の仕組みについて知る必要がありそうです。

少し調べていると、どうやら ソケット というのがキーワードになりそうだということがわかってきました。なんとなく知っている気でいたものの、仕組みについて詳しく調べたことはなかったので良い機会です。

さらにしばらく調べていると、下記の記事(途中から会員登録が必要ですが。。。)にまさに知りたかったことが書かれていました。

⇒ Linuxカーネルの基本機能 - 第12回 ソケット・インタフェース:ITpro

その他いろんな記事を読んでみてざっくりわかったことを整理すると、

  • Unix系OSは、元々デバイスドライバなど、なんでも「ファイル」をインタフェースとして扱う仕組みがあった。
  • 通信プロトコル(TCP/IPとか)にそのまま「ファイル」を適用するのが難しかったので、拡張した「ソケット」というインタフェースを考えだした。
  • ファイルを操作する時に、 ファイル識別子 という数値を取得する必要があったのと同じように、ソケットの場合も ソケット識別子 を取得してから扱う。
  • ソケットはファイルと同様に、iノード を使って管理される。
  • ソケットは作成時に「INETドメイン用(TCP/IPなど)」か「UNIXドメイン用(内部通信)」に分かれる。
iノードとは?

Unix系OSにて、ファイルやディレクトリを管理するためのデータです。ファイルの実体とは別の場所にあって、「パーミッション」「所有者」「参照数」「サイズ」「ディスク上での位置」「最終更新日時」などなど、ファイルに関する基本情報を持っています。

今回のようなポートを使ったサーバとクライアント間のTCP/IPでの通信では、INETドメインのソケットが作られることになります。

で、ソケットが作られて、実際にクライアントから接続されるまでの流れはこうです。

  1. サーバ側がソケットをINETドメイン用(TCP/IPなどで利用できる)に作成する。
    ⇒ socket()システムコール
  2. ポート番号を割り当てる。
    ⇒ bind()システムコール
  3. ソケット・キューを作成する。
    ⇒ listen()システムコール
  4. クライアントからの接続を待つ。
    ⇒ accept()システムコール

各システムコールで何を行うかは、下記記事がわかりやすいです。

⇒ Aufheben Software ソケット入門(1)

・・・と、掘り下げるのは今回はここでやめておきます。

まとめ

まとめると、 「とあるポート番号を使っているプロセスを調べる」ためには、そのポート番号が割り当てられたソケット(≒ファイル)を操作している(開いている)プロセスを調べればわかる ので、それをやってくれてるのが lsof コマンドだということになるかと。

おまけ

iノードについて調べてたら、こんな記事を見つけました。

ファイル削除直後に復元するということも lsof コマンドを使いこなせばできるみたいですねー。

⇒ Leverage OSS:削除したファイルをlsofで復元する - ITmedia エンタープライズ