c# - 处理套接字/完成两次的问题?

标签 c# sockets dispose finalizer xunit

我正在为一个打开套接字、发出请求并监听响应的类编写一些代码(不是我的,我赶紧添加,我根本不信任它),这会在在 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/

相关文章:

c# - 在应用程序设置中添加 Entity Framework 连接字符串作为变量

c# - 三层架构中的错误处理

c - 如何使用原始套接字在 C 中接收 ICMP 请求

ruby - Ruby 套接字编程中的标准套接字超时(秒)是多少?

sockets - 何时关闭套接字 tcp

c# - 动态更改 TextView 的文本

c# - 是否将 LINQ 上下文存储为请求变量?

C# USING 关键字 - 何时何地不使用它?

java - 处置容器是否会删除所有已注册的监听器?

c# - 当对象设置为 null 时,针对 CLR 的编译器能否生成 Dispose 方法调用?