您好,我正在尝试找到一种方法来“解除”套接字与特定 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#,基于标记)文件流是一个常见的例子。

您必须确保释放该对象所持有的资源,以便可以对其进行垃圾收集。否则它不会被垃圾收集,而是保留在内存中的某个地方。您的伪代码示例并未提供您正在释放资源,您只是声明该对象被(应该)被垃圾收集。

垃圾收集器不保证套接字将永远关闭。有关完整的示例,请阅读此内容 MSDN 示例.

重点是实际调用 Socket.Close() 尽快地。例如,ClassA 可以实现 I一次性 并像这样使用它:

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.aspxhttp://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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top