我正在为一个打开套接字、发出请求并监听响应的类编写一些代码(不是我的,我赶紧添加,我根本不信任它),这会在在 xunit 中测试时我无法理解的方式。我假设相同的异常发生“实时”,但该类由单例引用,因此它可能只是隐藏了。
问题在 xunit 中表现为“System.CannotUnloadAppDomainException:卸载 appdomain 时出错”,内部异常是关闭套接字时在终结器内部(本质上)抛出的“System.ObjectDisposedException”!在 Socket 类上没有对调用关闭和处置的套接字的其他引用受到保护,因此我不清楚如何处置该对象。
此外,如果我只是捕获并吸收 ObjectDisposedException,xunit 在它到达关闭监听器线程的行时终止。
我只是不明白在要求关闭之前如何处理 Socket。
我对套接字的了解只是我发现这个问题后学到的知识,所以我不知道我是否提供了 SO 可能需要的一切。 LMK 如果没有!
public class Foo
{
private Socket sock = null;
private Thread tListenerThread = null
private bool bInitialised;
private Object InitLock = null;
private Object DeInitLock = null;
public Foo()
{
bInitialised = false;
InitLock = new Object();
DeInitLock = new Object();
}
public bool initialise()
{
if (null == InitLock)
return false;
lock (InitLock)
{
if (bInitialised)
return false;
sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 8);
sock.Bind( /*localIpEndPoint*/);
sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(mcIP));
tListenerThread = new Thread(new ThreadStart(listener));
tListenerThread.Start();
bInitialised = true;
return true;
}
}
~Foo()
{
if (bInitialised)
deInitialise();
}
private void deInitialise()
{
if (null == DeInitLock)
return;
lock (DeInitLock)
{
if (bInitialised)
{
sock.Shutdown(SocketShutdown.Both); //throws System.ObjectDisposedException
sock.Close();
tListenerThread.Abort(); //terminates xunit test!
tListenerThread = null;
sock = null;
bInitialised = false;
}
}
}
}
最佳答案
如果此对象符合垃圾回收条件并且没有其他对 Socket 的引用,则 socket 的 终结器很可能在对象的终结器之前运行。我怀疑这就是这里发生的事情。
在终结器中完成这么多工作通常不是一个好主意(IMO)。我完全不记得我上次实现终结器是什么时候了——如果你实现了 IDisposable,你应该没问题,除非你有直接对非托管资源的引用,这些资源几乎总是以 IntPtrs 的形式出现。有序关闭应该是常态 - 终结器通常只应在程序关闭或有人忘记处置实例时才运行。
(我知道您在一开始就澄清了这不是您的代码 - 我只是想我会解释为什么它有问题。如果您已经了解部分/全部内容,我们深表歉意。)
关于c# - 处理套接字/完成两次的问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/423794/