socket - python3 tcp example




Python:バインディングソケット: "Address already in use" (8)

TCP / IPネットワーク上のクライアントソケットに関する質問があります。 私が

try:

    comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

except socket.error, msg:

    sys.stderr.write("[ERROR] %s\n" % msg[1])
    sys.exit(1)

try:
    comSocket.bind(('', 5555))

    comSocket.connect()

except socket.error, msg:

    sys.stderr.write("[ERROR] %s\n" % msg[1])

    sys.exit(2)

作成されたソケットはポート5555にバインドされます。問題は、接続を終了した後

comSocket.shutdown(1)
comSocket.close()

wiresharkを使用して、私は両方の側からのFIN、ACKとACKで閉じたソケットを見る、私は再びポートを使用することはできません。 次のエラーが表示されます。

[ERROR] Address already in use

私はすぐにポートをクリアすることができますので、次回は同じポートを使用することができます。

comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

setsockoptは問題を解決できないようです。ありがとうございました!


Felipe Cruzeが述べたように、バインドする前にSO_REUSEADDRを設定する必要があります。 他のサイトのソリューションを見つけました - 他のサイトのソリューション

問題は、アドレスがソケットにバインドされる前にSO_REUSEADDRソケットオプションを設定する必要があることです。 これは、ThreadingTCPServerをサブクラス化し、server_bindメソッドを次のようにオーバーライドすることによって実行できます。

import SocketServer, socket

class MyThreadingTCPServer(SocketServer.ThreadingTCPServer):
    def server_bind(self):
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)


SO_REUSADDRは、TIME_WAITにスタックされているポートを使用することを許可しますが、そのポートを使用して、接続先の最後の場所への接続を確立することはできません。 何? ローカルポート1010を選択し、foobar.comポート300に接続し、ローカルで閉じてTIME_WAITにそのポートを残すとします。 私はローカルポート1010をすぐに再利用して、foobar.comポート300以外のどこにでも接続できます。

ただし、リモートエンドがクロージャ(クローズイベント)を開始するようにすることで、TIME_WAIT状態を完全に回避することができます。 したがって、サーバーはクライアントを最初に閉じることによって問題を回避できます。 アプリケーションプロトコルは、クライアントがいつ閉じるべきかを知るように設計されなければならない。 サーバーはクライアントからのEOFに応答して安全に閉じることができますが、クライアントがネットワークを慎重に離脱した場合にEOFを期待しているときにタイムアウトを設定する必要があります。 多くの場合、サーバーが終了するまで数秒待つだけで十分です。

また、ネットワーキングとネットワークプログラミングの詳細については、アドバイスをいただきます。 あなたは少なくともtcpプロトコルがどのように働くべきかを知っておくべきです。 プロトコルは非常に些細で小さいので、将来あなたに多くの時間を節約するかもしれません。

netstatコマンドを使用すると、どのプログラム((program_name、pid)tuple)がどのポートにバインドされているのか、ソケットの現在の状態(TIME_WAIT、CLOSING、FIN_WAITなど)を簡単に確認できます。

Linuxのネットワーク構成についての本当の良い説明は、 https://serverfault.com/questions/212093/how-to-reduce-number-of-sockets-in-time-wait


socket.socket()socket.socket()前に実行して、 socket.bind()を使用してREUSEADDR


ここでは、私がテストした完全なコードがありますが、私には「アドレスはすでに使用中です」というエラーはありません。 これをファイルに保存し、提供したいHTMLファイルのベースディレクトリ内からファイルを実行することができます。 また、サーバーを起動する前にプログラムでディレクトリを変更することもできます

import socket
import SimpleHTTPServer
import SocketServer
# import os # uncomment if you want to change directories within the program

PORT = 8000

# Absolutely essential!  This ensures that socket resuse is setup BEFORE
# it is bound.  Will avoid the TIME_WAIT issue

class MyTCPServer(SocketServer.TCPServer):
    def server_bind(self):
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)

Handler = SimpleHTTPServer.SimpleHTTPRequestHandler

httpd = MyTCPServer(("", PORT), Handler)

# os.chdir("/My/Webpages/Live/here.html")

httpd.serve_forever()

# httpd.shutdown() # If you want to programmatically shut off the server

ターミナルのfuser -k [PORT NUMBER]/tcpfuser -k 5001/tcpなど)を入力するだけで、そのポートでプロセスを強制終了するのが最善の方法です。


バインディングの前にallow_reuse_addressを設定する必要があります。 SimpleHTTPServerの代わりにこのスニペットを実行します:

Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler, bind_and_activate=False)
httpd.allow_reuse_address = True
httpd.server_bind()
httpd.server_activate()
httpd.serve_forever()

これにより、フラグを設定する機会が来る前にサーバがバインドされるのを防ぐことができます。


私にとっては、より良い解決策は次のとおりでした。 接続を閉じるというイニシアチブがサーバによって行われたため、 setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)は何の効果もなく、TIME_WAITは同じポート上で新しい接続をエラーで回避していました。

[Errno 10048]: Address already in use. Only one usage of each socket address (protocol/IP address/port) is normally permitted 

私は最終的にOSがポート自体を選択できるようにソリューションを使用しました。そして、先例がまだTIME_WAITの場合は別のポートが使用されます。

私は置き換えた:

self._socket.bind((guest, port))

with:

self._socket.bind((guest, 0))

それは、tcpアドレスのpythonソケットのドキュメントに示されているように:

source_addressが指定されている場合は、接続する前にソースアドレスとしてバインドするソケットの2タプル(ホスト、ポート)でなければなりません。 ホストまたはポートがそれぞれ ''または0の場合、OSのデフォルト動作が使用されます。


私はあなたがすでに答えを受け入れたことは知っていますが、問題はクライアントソケットでbind()を呼び出すことと関係していると思います。 これは問題ありませんが、bind()とshutdown()はうまくいっていないようです。 また、SO_REUSEADDRは一般的にリッスンソケットとともに使用されます。 すなわちサーバ側で実行される。

あなたは渡すべきであり、connect()へのip / port。 このような:

comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
comSocket.connect(('', 5555))

bind()を呼び出さず、SO_REUSEADDRを設定しないでください。





port