非常に大規模なプロジェクトの開発の過程で、多くの単体テストを蓄積してきました。これらのテストの多くは、サーバーの起動、これらのサーバーへの接続、およびサーバーとクライアントの終了を、通常は同じプロセスで行います。
ただし、これらのテストは、「アドレス 127.0.0.1:(ポート) のバインドに失敗しました」というエラーでランダムに失敗します。テストを再実行すると、通常、エラーは消えます。
さて、これは私たちのテストの問題だと思いましたが、Clojure で小さなテストを書くことにしました。
(ns test
(:import [java.net Socket ServerSocket]))
(dotimes [n 10000] ; Run the test ten thousand times
(let [server (ServerSocket. 10000) ; Start a server on port 10000
client (Socket. "localhost" 10000) ; Start a client on port 10000
p (.getLocalPort client)] ; Get the local port of the client
(.close client) ; Close the client
(.close server) ; Close the server
(println "n = " n) ; Debug
(println "p = " p) ; Debug
(println "client = " client) ; Debug
(println "server = " server) ; Debug
(let [server (ServerSocket. p)] ; Start a server on the local port of the client we just closed
(.close server) ; Close the server
(println "client = " client) ; Debug
(println "server = " server) ; Debug
))
)
例外は、2 番目のサーバーを起動する行にランダムに表示されます。そのポートのクライアントがすでに閉じられているにもかかわらず、Java がローカル ポートを保持しているように見えます。
では、私の質問: Java がこれを行っているのはなぜでしょうか。
EDIT :誰かが、ソケットの reuseAddr を true に設定することを提案しました。私はこれを行いましたが、何も変わっていないので、以下のコードです。
(ns test
(:import [java.net Socket ServerSocket InetSocketAddress]))
(dotimes [n 10000] ; Run the test ten thousand times
(let [server (ServerSocket. )] ; Create a server socket
(. server (setReuseAddress true)) ; Set the socket to reuse address
(. server (bind (InetSocketAddress. 10000))) ; Bind the socket
(let [client (Socket. "localhost" 10000) ; Start a client on port 10000
p (.getLocalPort client)] ; Get the client's local port
(.close client) ; Close the client
(.close server) ; Close the server
; (. Thread (sleep 1000)) ; A sleep for testing
(println "n = " n) ; Debug
(println "p = " p) ; Debug
(println "client = " client) ; Debug
(println "server = " server) ; Debug
(let [server (ServerSocket. )] ; Create a server socket
(. server (setReuseAddress true)) ; Set the socket to reuse address
(. server (bind (InetSocketAddress. p))) ; Bind the socket to the local port of the client we just had
(.close server) ; Close the server
(println "client = " client) ; Debug
(println "server = " server) ; Debug
)))
)
また、10 ミリ秒または 100 ミリ秒のスリープでも問題が回避されないことにも気付きました。ただし、1000msec は (これまでのところ) それを防ぐことができました。
編集 2 : 誰かが私を SO_LINGER に入れましたが、ServerSockets でそれを設定する方法が見つかりません。誰でもそれについて何か考えがありますか?
EDIT 3 : SO_LINGER がデフォルトで無効になっていることが判明しました。他に何を見ることができますか?
更新: 10,000 程度のポートの範囲で動的ポート割り当てを使用することで、問題はほとんど解決されました。しかし、私はまだ人々が何を思い付くことができるかを見たいと思っています.