无法将套接字重新绑定到现有的IP/端口组合。

4

你好,我正在尝试找到一种方法来从特定的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)),但这些都不能取消绑定套接字。

任何帮助将不胜感激!

5个回答

3

这是让我最终成功的方法:

确保A连接的每个套接字都有

socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress, true);

在启动时设置。


这是否意味着先前的套接字仍然存在并绑定到该端口? http://msdn.microsoft.com/en-us/library/cc319473.aspxReuseAddress是您用于允许绑定到已经在使用中的地址的值。正在使用中,而不是已经被使用过 - VolkerK
VolkerK;我认为你是对的。这就是你必须小心并确保先前的实例真的消失了的地方;默认情况下,伯克利套接字将等待5分钟才释放端口/套接字组合;这是我找到的唯一可行的解决方法。 - AlexeyMK

0

垃圾回收器不能保证套接字会被关闭。要查看完整的示例,请阅读MSDN示例

关键是尽快调用Socket.Close()。例如,ClassA可以实现IDisposable并像这样使用它:

using (ClassA a = new ClassA()) 
{
    // code goes here
}
// 'a' is now disposed and the socket is closed

0

最好的解决方案是尝试绑定套接字几次(2-3次)。在第一次尝试失败时,我发现它将正确地(且永久地)关闭原始套接字。

希望有所帮助,

_NT


0

在C#中,你不能依赖于对象被垃圾回收(我假设你正在使用C#,基于标记)如果它持有资源,比如像在你的例子中绑定到网络资源,或者持有某种流,文件流是一个常见的例子。

你必须确保释放对象所持有的资源,以便它可以被垃圾回收。否则它将不会被垃圾回收,而是仍然存活在内存中。你的伪代码示例并没有提供你正在执行资源释放,你只是说明对象应该被垃圾回收。


0
垃圾回收器在某个不确定的时间运行对象的终结器。 您可以实现IDisposable接口并在对象失去作用域之前调用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()) { } } } }

可能是因为使用了不同的IP地址,所以IPAddress.Any才能使其正常工作。无论如何,这并不能解决问题(抱歉表述不清):ClassA是一个网络通信管理器类,而Socket是一个类范围内的变量。 - AlexeyMK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接