【问题标题】:Getting an ObjectDisposed exception when calling Shutdown then Close on a Socket在调用 Shutdown 然后在 Socket 上关闭时获取 ObjectDisposed 异常
【发布时间】:2012-10-04 16:35:46
【问题描述】:

我有一个 SocketState 对象,用于将缓冲区和套接字包装在一起,并将其传递给 Begin/End 异步套接字方法。在析构函数中,我有这个:

~SocketState()
{
    if (!_socket.Connected) return;

    _socket.Shutdown(SocketShutdown.Both);
    _socket.Close();
}

当它到达 Close() 时,我得到一个 ObjectDisposed 异常。如果我注释掉调用 Shutdown(),当它到达 Close() 方法时,我不会收到错误消息。我做错了什么?

编辑:

我知道 IDisposable 解决方案似乎是我的代码应该布局的方式,但这实际上并不能解决我的问题。它不像析构函数被调用两次,那么为什么调用 dispose() 而不是使用析构函数对我有帮助呢?连续调用这两个函数时,我仍然遇到同样的异常。

我查看了类似服务器的源代码,他们所做的只是将这两个语句包装在一个 try 块中并吞下异常。如果必须,我会这样做,因为它看起来无害(无论如何我们都会关闭它),但如果可能的话,我想避免它。

【问题讨论】:

    标签: c# networking sockets


    【解决方案1】:

    使用反射器;看来Close() 本质上只是在套接字上调用Dispose()(它在任一侧都进行了一些记录)。查看Shutdown(),它在套接字句柄上调用ws2_32.dll!shutdown()Dispose() 调用。可能发生的是它试图在同一个套接字句柄上调用ws2_32.dll!shutdown() 两次。

    简而言之,只需致电Close()

    【讨论】:

    • 这听起来很合理,但 MSDN 文档明确指出您应该在关闭之前调用 shutdown 以便它完成发送/接收数据。
    • 有趣;这可能是因为您在 Finalizer 中进行工作;我建议采纳 Jeroen Landheer 的 建议,实施 IDisposable 是优雅地做到这一点的方法。
    【解决方案2】:

    _socket 实现了 IDisposable,当你的终结器运行时,套接字已经被释放(或就此而终结)。

    你应该在你的类上实现 IDisposable 并遵循 dispose 模式。

    例子:

    public class SocketState : IDisposable
    {
      Socket _socket;
    
      public SocketState()
      {
        _socket = new Socket();
      }
    
      public bool IsDisposed { get; private set; }
    
      public void SomeMethod()
      {
        if (IsDisposed)
          throw new ObjectDisposedException("SocketState");
    
        // Some other code
      }
    
      #region IDisposable Members
    
      public void Dispose()
      {
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    
      protected virtual void Dispose(bool disposing)
      {
        if (!IsDisposed)
        {
          if (disposing)
          {
            if (_socket != null)
            {
              _socket.Close();
            }
          }
    
          // disposed unmanaged resources
    
          IsDisposed = true;
        }
      }
    
      ~SocketState()
      {
        Dispose(false);
      }
    
      #endregion
    }
    

    【讨论】:

    • 我仍然需要调用 Shutdown() 来完成发送数据(根据 MDSN 文档)。您提供的示例并没有真正帮助任何事情..无论我从哪里调用代码都会出现相同的错误。
    • 正如您在 Phil 的帖子中看到的,处理套接字就足够了。但是如果你真的想先调用 Shutdown,把调用放在 _socket.Close() 之前,并在 _socket.Dispose() 中更改 _socket.Close
    【解决方案3】:

    您的问题有些不清楚。你说,当

    它到达Close(),你得到一个ObjectDisposedException

    但是看,Close 不会抛出任何东西。确实抛出了ObjectDisposedException 的是Shutdown。这可能就是为什么评论 Shutdown 会有所帮助 - 这正是您获得异常的地方。

    我的解释是,在您的主对象最终确定之前,您的套接字会自动获得.Dispose()(通过它自己的终结器)。

    正如here所说:

    终结器的执行顺序是不确定的——换句话说,您不能依赖在终结器中仍然可用的另一个对象。

    【讨论】:

      猜你喜欢
      • 2022-01-27
      • 1970-01-01
      • 1970-01-01
      • 2018-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多