ソケットを既存の IP/ポートの組み合わせに再バインドできない
-
09-06-2019 - |
質問
こんにちは。特定の IP/ポートの組み合わせからソケットを「バインド解除」する方法を見つけようとしています。私の擬似コードは次のようになります。
ClassA a = new ClassA(); //(class A instantiates socket and binds it to 127.0.0.1:4567)
//do something
//...much later, a has been garbage-collected away.
ClassA aa = new ClassA(); //crash here.
この時点で、.Net はソケットが 127.0.0.1:4567 にバインドされていることを通知しますが、これは技術的には真実です。しかし、ClassA のデストラクターにどのようなコードを入れても、またはソケットでどのような関数を呼び出しても (.Close() と .Disconnect(true) を試しました)、ソケットは堂々と 127.0.0.1:4567 にバインドされたままになります。ソケットの「バインドを解除」するにはどうすればよいですか?
編集:私はガベージ コレクションだけに依存しているわけではありません (そのアプローチも試しましたが)。a.Close() または a.Disconnect() を呼び出してから、aa をインスタンス化してみました。これでは問題は解決しません。
編集:IDisposable の実装も試みましたが、メソッドを呼び出さない限りコードはそこに到達しませんでした (これは、メソッドが .Close と .Disconnect を試行するだけなので、以前の試みと同等でした)。.Dispose に直接電話して、折り返しご連絡させていただきます。
編集(多くの編集、お詫び):IDisposable を実装し、「a」がスコープを失った場所から a.Dispose() を呼び出すと機能しません。私の Dispose 実装では、依然として .Close または .Disconnect(true) (または .Shutdown( Both)) のいずれかを呼び出す必要がありますが、それらはどれもバインドを解除しません。ソケット。
助けていただければ幸いです。
解決
(これが最終的に私にとってすべてうまくいくようになったものです)
A のソケットが接続するすべてのソケットに
socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress, true);
開始時に設定されます。
他のヒント
例のようにネットワークリソースにバインドされている場合や、他の種類のストリームを保持している場合など、オブジェクトがC#でガベージコレクションされていることに依存することはできません(タグ付けに基づいてC#を使用していると仮定します)。ファイル ストリームが一般的な例です。
オブジェクトがガベージ コレクションできるように、オブジェクトが保持しているリソースを確実に解放する必要があります。そうしないと、ガベージ コレクションされず、メモリのどこかに存在したままになります。あなたの疑似コードの例では、リソースの解放を行っていることは規定されておらず、オブジェクトがガベージコレクションを取得する(取得する必要がある)とだけ述べています。
ガベージ コレクターは、不定の時点でオブジェクトのファイナライザーを実行します。IDisposable インターフェイスを実装して、オブジェクトがスコープを失う前に Dispose() メソッドを呼び出すことも、using ステートメントにそれを行わせることもできます。
見る http://msdn.microsoft.com/en-us/library/system.idisposable.aspx そして http://msdn.microsoft.com/en-us/library/yh598w02.aspx
編集:私にとってはうまくいきます
using System; using System.Net.Sockets; using System.Net; namespace ConsoleApplication1 { class Program { class ClassA : IDisposable { protected Socket s; public ClassA() { s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); s.Bind(new IPEndPoint(IPAddress.Any, 5678)); } public void Dispose() { s.Close(); } } static void Main(string[] args) { using(ClassA a=new ClassA()) { } using (ClassA b = new ClassA()) { } } } }
最善の解決策は、ソケットのバインドを数回 (2 ~ 3 回) 再試行することです。最初の試行で失敗した場合、元のソケットが適切に (そして永久に) 閉じられることがわかりました。
HTH、
_NT