dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[python]SimpleHttpServerがCtrl+Cで終了しないとき

以前 D3.js を使ってみた時の記事でも紹介したが、

pythonSimpleHttpServer (python 2.x 系の場合) を使うと簡単にローカルサーバーを起動することができる。

# python 2.X
$ python -m SimpleHTTPServer [ポート番号]

# python 3
$ python -m http.server [ポート番号]

ターミナルで上記のコマンドを実行した後、http://localhost:[ポート番号] にアクセスするだけです。
また、コマンドを実行した時のディレクトリがルートディレクトリになる。

コマンド自体はこれだけなんだけど、ちょっとしたハマりどころがあったのでメモ。

注意点

ここから、実際にはまったポイントとその解決策。
まず、

$ python -m SimpleHttpServer 8080 &

とした後、作業が終わったので Ctrl+C でローカルサーバーを終了。

しばらくして、別の目的でもう一度ローカルサーバーを起動するべく上記のコマンドを実行。
すると...

# さっきと全く同じコマンド
$ python -m SimpleHttpServer 8080 &
Traceback (most recent call last):
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/SimpleHTTPServer.py", line 220, in <module>
    test()
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/SimpleHTTPServer.py", line 216, in test
    BaseHTTPServer.test(HandlerClass, ServerClass)
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/BaseHTTPServer.py", line 595, in test
    httpd = ServerClass(server_address, HandlerClass)
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/SocketServer.py", line 419, in __init__
    self.server_bind()
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/BaseHTTPServer.py", line 108, in server_bind
    SocketServer.TCPServer.server_bind(self)
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/SocketServer.py", line 430, in server_bind
    self.socket.bind(self.server_address)
  File "/Users/*****/.pyenv/versions/2.7.5/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 48] Address already in use

あれ?

おかしいなと思って http://localhost:8080 にアクセスしてみると、
たしかに前のローカルサーバーが起動したままになってる。

で、

結論としては、コマンドの最後に & をつけていたことが原因のよう。

参考: terminal - terminate simple python server wont shut down with ctrl + C - Stack Overflow

& をつけてコマンドを実行したので、バックグラウンドでプロセス (この場合、ローカルサーバーの起動) が残ってたんですね。
後で確認しましたが、& つけなければちゃんと Ctrl+C で終了します。

さて、なのでやるべきは該当のプロセスを見つけることと、そのプロセスを明示的に終了させること。

該当のプロセスを見つける

現在実行中のプロセス一覧を表示するのに ps コマンドを使う。

参考: http://codezine.jp/unixdic/w/ps

$ ps
  PID TTY           TIME CMD
  356 ttys000    0:00.14 -zsh
  479 ttys000    0:00.01 /bin/bash /usr/local/bin/tmuxx
  488 ttys000    0:00.01 tmux -f /dev/fd/63 new-session
  491 ttys001    0:00.27 -zsh
  859 ttys002    0:00.43 -zsh
 1922 ttys002    0:00.32 /Applications/MacVim.app/Contents/MacOS/Vim
 1706 ttys003    0:00.46 -zsh
 2642 ttys004    0:00.31 -zsh
 3514 ttys004    0:00.30 python -m SimpleHTTPServer 8080

実行した時はこんな感じだった。
たしかに、一番下の行に python -m ... があるのがわかる。

この時、プロセスの PID の部分はプロセスの終了に使うので覚えておく。

プロセスを終了する

プロセスを終了するには kill コマンドを使う。

$ kill -15 [PID]

# または、
$ kill -TERM [PID]

15 とか TERM とかなんだ?って思って調べてみたらここに書いてあった。

UNIXコマンド - kill

kill の後ろに指定するものは シグナル と呼び、いくつか種類がある。
そして 15番 が正常終了のシグナルで、TERM というシグナル名がついている、ということのようですね。

まとめ

  • python -m SimpleHttpServer& つけて実行しない
    (たぶん & つけないといけない状況ってない)
  • 起動中のプロセスは ps で確認
  • 任意のプロセスを終了するには kill -15 [PID] を実行