19

サーバーを実行するための私のコードは次のとおりです。

class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    #....

PORT = 8089

httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler)
httpd.allow_reuse_address = True

print "Serving forever at port", PORT
try:
    httpd.serve_forever()
except:
    print "Closing the server."
    httpd.server_close()
    raise

しかし、これは何が起こるかです:

^CClosing the server.
Traceback (most recent call last):
  File "server.py", line 118, in <module>
    self.send_error(400, "Unimplemented GET command: %s" % (self.path,))
  File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 224, in serve_forever
    r, w, e = select.select([self], [], [], poll_interval)
KeyboardInterrupt
(.virtualenv)claudiu@xxx:~/xxx$ python server.py
Traceback (most recent call last):
  File "server.py", line 122, in <module>
    httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler)
  File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 402, in __init__
    self.server_bind()
  File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 413, in server_bind
    self.socket.bind(self.server_address)
  File "<string>", line 1, in bind
socket.error: [Errno 98] Address already in use

なんで?サーバーを閉じallow_reuse_addressてTrueに設定します...Python2.6.8を使用します。

4

4 に答える 4

26

他の答えのおかげで、私はそれを理解しました。allow_reuse_addressインスタンスではなく、クラスに存在する必要があります。

SocketServer.TCPServer.allow_reuse_address = True
httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler)

ただし、ソケットを閉じてもサーバーの次の実行のためにソケットが解放されなかった理由はまだわかりません。

于 2013-03-07T17:54:04.293 に答える
13

これ[Err 98] Address already in useは、ソケットが.close()あったという事実によるものですが、リモートTCPが接続終了要求の確認応答を受信したことを確認するために、まだ十分な時間が経過するのを待っています(TIME_WAITを参照)。デフォルトでは、そのポートにバインドされたソケットがある場合、ソケットをバインドすることはできませんが、allow_reuse_address(SO_REUSEADDR)でオーバーライドできます。

(この他の回答TCPServer.allow_reuse_addrで提案されているように)変更することは可能ですが、次のように設定されている独自のサブクラスの方がクリーンだと思います。TCPServerallow_reuse_addressTrue

import SocketServer
import SimpleHTTPServer
import time

class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET():
        time.sleep(60)
        self.request.sendall("I'm here!")

class ReuseAddrTCPServer(SocketServer.TCPServer):
    allow_reuse_address = True

PORT = 8089

httpd = ReuseAddrTCPServer(("", PORT), MyRequestHandler)
httpd.daemon_threads = True


print "Serving forever at port", PORT
try:
    httpd.serve_forever()
except:
    print "Closing the server."
    httpd.server_close()
    raise

allow_reuse_addressインスタンス自体に(クラスをいじることなく)確実に設定されたものを使用できますが、を使用する必要がありますTCPServer(..., bind_and_activate=False)。そうしないと、設定を変更する前にソケットがバインドされますallow_reuse_address。次に、手動で呼び出す必要が.server_bind()あり.server_activate()ますserve_forever()

...
httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler, bind_and_activate=False)
httpd.allow_reuse_address = True
httpd.daemon_threads = True
...
httpd.server_bind()
httpd.server_activate()
httpd.serve_forever()
于 2017-02-09T22:17:29.780 に答える
3

これは、TCPTIME_WAITが原因です。

誰かがこの正確な問題を発見しました。

ただし、変更をテストするためにサーバーを停止して再起動しようとすると、ランダムな「socket.error:[Errno98]アドレスはすでに使用されています」というエラーが発生します。これは、クライアントがすでにサーバーに接続している場合にのみ発生します。

netstatとpsを確認すると、プロセス自体は実行されていませんが、ソケットはステータス「TIME_WAIT」のポートをリッスンしていることがわかりました。基本的に、OSは、この接続に途中でパケットが残っていないことを確認するためにしばらく待機します。

于 2013-03-07T04:25:31.817 に答える
0

これは、ソケットをバインドする前にSO_REUSEADDRESSを設定する必要があるためです。ソケットをすべて1つのステップで作成してバインドし、それを設定しているので、もう手遅れです。

于 2013-03-07T05:11:19.027 に答える