无法将套接字重新绑定到现有的IP /端口组合
问候,我试图找到一种方法来从特定的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)。让我尝试致电。直接处理并联系我们。
编辑(许多编辑,道歉):实现IDisposable并从a失去作用域的地方调用a.Dispose()不起作用,我的Dispose实现仍然必须调用.Close或者.Disconnect(true)(或者.Shutdown(两者)),但没有一个解除绑定套接字。
任何帮助,将不胜感激!
解决方案
回答
如果对象包含像绑定到网络资源那样的资源(如示例),或者包含其他某种类型的流,则我们不能依靠对象在C中进行垃圾收集(我假设我们使用的是基于标记的c#)文件流将是一个常见的示例。
我们必须确保释放该对象所拥有的资源,以便可以对其进行垃圾回收。否则将不会被垃圾收集,而是保留在内存中的某个位置。伪代码示例未提供我们正在执行资源释放的过程,我们只是声明对象已(应该)被垃圾回收。
回答
垃圾收集器不能保证我们将关闭套接字。有关完整的示例,请阅读此MSDN示例。
要点是尽快实际调用Socket.Close()
。例如,ClassA可以实现IDisposable并像这样使用它:
using (ClassA a = new ClassA()) { // code goes here } // 'a' is now disposed and the socket is closed
回答
垃圾收集器会在不确定的时间运行对象的终结器。
我们可以实现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()) { } } } }
回答
(这终于使一切都能为我工作)
确保A中的插座所连接的每个插座都具有
socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress, true);
在启动时设置。
回答
最好的解决方案是重试几次绑定套接字(2-3)。第一次尝试,如果失败,我发现它将正确(永久)关闭原始套接字。
HTH,
_NT