无法将套接字重新绑定到现有的 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 接口并在对象失去 Scope 之前调用 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)。在第一次尝试时,如果失败,我发现它将正确(且永久)关闭原始套接字。
哈特哈,
_NT