web-dev-qa-db-ja.com

ソケットエラー:アドレスは既に使用されています

サーバーを起動するために頻繁に実行するCherryPyスクリプトがあります。今日、設定ファイルのいくつかのバグを修正するために数回起動および停止する必要がありました。ソケットを再起動しようとしたときに次の問題が発生したため、ソケットが完全に閉じなかったと思います。

[23/Mar/2015:14:08:00] ENGINE Listening for SIGHUP.
[23/Mar/2015:14:08:00] ENGINE Listening for SIGTERM.
[23/Mar/2015:14:08:00] ENGINE Listening for SIGUSR1.
[23/Mar/2015:14:08:00] ENGINE Bus STARTING
CherryPy Checker:
The Application mounted at '' has an empty config.

[23/Mar/2015:14:08:00] ENGINE Started monitor thread 'Autoreloader'.
[23/Mar/2015:14:08:00] ENGINE Started monitor thread '_TimeoutMonitor'.
[23/Mar/2015:14:08:00] ENGINE Error in HTTP server: shutting down
Traceback (most recent call last):
  File "/home/andrew/virtualenvs/mikernels/lib/python2.7/site-packages/cherrypy/process/servers.py", line 188, in _start_http_thread
    self.httpserver.start()
  File "/home/andrew/virtualenvs/mikernels/lib/python2.7/site-packages/cherrypy/wsgiserver/wsgiserver2.py", line 1848, in start
    raise socket.error(msg)
error: No socket could be created

CherryPyのwsgiserver2.pyを編集して、socket.errorとerror.strerror

98  (98, 'Address already in use') Address already in use

一方、私のソケットは次のように構成されています:

af = 2
socktype = 1
proto = 6
canonname = ''
sa = ('0.0.0.0', 2112)
self.bind(af, socktype, proto)

(これは正確なコードではありませんが、エラーが発生したときの値です)

Netstatをチェックしたところ、ポート2112でリッスンしているものは何もありませんでした。何が問題の原因であり、どのように診断すればよいですか?

ありがとう!

7
Andrew Latham

以下を試すことができます

from socket import *

sock=socket()
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# then bind

ドキュメントから:

SO_REUSEADDRフラグは、本来のタイムアウトが切れるのを待たずに、TIME_WAIT状態のローカルソケットを再利用するようにカーネルに指示します。

ここに完全な説明があります:

実行間の遅延が小さすぎる例を数回実行すると、このエラーが発生する可能性があります。

socket.error: [Errno 98] Address already in use

これは、前回の実行でソケットがTIME_WAIT状態のままになり、すぐに再利用できないためです。

これを防止するために設定するソケットフラグがあります。socket.SO_REUSEADDR:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((Host, PORT))
18
ForceBru

次のようにして、プロセスを見つけてkillできます。

ps aux | grep python

、プロセスIDを見つけ、次のようにして手動で停止します。

Sudo kill -9 PID

pIDをPIDに置き換えます。

Flask/CherryPyでテストしている間、私はしばしばこれをしなければなりません。より簡単な方法があるかどうかに興味があります(たとえば、そもそもそれを防ぐため)

13
Ryan

それを行うのははるかに簡単です:

PIDを確認します(127.0.0.1:5000で実行して以来、:5000はホストです):
$ lsof -i :5000
それからそれを殺します:
$ Sudo kill -9 PID

12
Lord Salforis