C# 异步套接字在我关闭套接字时崩溃

C# 异步套接字在我关闭套接字时崩溃,c#,sockets,C#,Sockets,下面显示的代码几乎可以正常工作。如果我创建它的一个实例并调用“Connect”,那么一切都可以正常工作。当我调用“Disconnect”时,有时一切都很好(主要是如果我添加一个断点并缓慢地逐步完成函数)。如果我不使用断点,该类(作为win forms应用程序托管)似乎会消失(表单会消失),但VisualStudio仍然认为它正在运行。在VisualStudio的输出窗口中,我看到“System.dll中发生了类型为'System.ObjectDisposedException'的首次异常”。谁能

下面显示的代码几乎可以正常工作。如果我创建它的一个实例并调用“Connect”,那么一切都可以正常工作。当我调用“Disconnect”时,有时一切都很好(主要是如果我添加一个断点并缓慢地逐步完成函数)。如果我不使用断点,该类(作为win forms应用程序托管)似乎会消失(表单会消失),但VisualStudio仍然认为它正在运行。在VisualStudio的输出窗口中,我看到“System.dll中发生了类型为'System.ObjectDisposedException'的首次异常”。谁能看出我做错了什么

// State object for reading client data asynchronously
public class StateObject
{
    private Guid ID = Guid.NewGuid();
    // Client socket.
    public Socket workSocket = null;
    // Size of receive buffer.
    public const int BufferSize = 1024;
    // Receive buffer.
    public byte[] buffer = new byte[BufferSize];
}

public class NetworkComms : IBasePanel
{
    private static ILog _log = LogManager.GetCurrentClassLogger();

    // ManualResetEvent instances signal completion.
    private static ManualResetEvent connectDone = new ManualResetEvent(false);
    private static ManualResetEvent sendDone = new ManualResetEvent(false);
    private static ManualResetEvent receiveDone = new ManualResetEvent(false);

    private static Socket _client = null;
    private static IPEndPoint _endpoint = null;

    public event ReceiveMessageEventHandler OnReceiveMessage; 

    public NetworkComms(string address, int port)
    {
        _endpoint = new IPEndPoint(GetIPAddress(address), port);
    }

    private IPAddress GetIPAddress(string address)
    {
        IPAddress ipAddress = null;

        if (IPAddress.TryParse(address, out ipAddress))
        {
            return ipAddress;
        }
        else
        {
            IPHostEntry ipHostInfo = Dns.GetHostEntry(address);
            return ipHostInfo.AddressList[ipHostInfo.AddressList.Count() - 1];
        }
    }

    private  void ConnectCallback(IAsyncResult ar)
    {
        // Retrieve the socket from the state object.
        Socket client = (Socket)ar.AsyncState;

        // Complete the connection.
        client.EndConnect(ar);

        _log.DebugFormat("Socket connected to {0}", client.RemoteEndPoint.ToString());

        // Signal that the connection has been made.
        connectDone.Set();
    }

    private void Receive()
    {
        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = _client;

        // Begin receiving the data from the remote device.
        _client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
        // Retrieve the state object and the client socket 
        // from the asynchronous state object.
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.workSocket;

        // Read data from the remote device.
        int bytesRead = client.EndReceive(ar);

        if (bytesRead > 0)
        {
            // There might be more data, so store the data received so far.
            ReceivedNewMessage(Encoding.Default.GetString(state.buffer, 0, bytesRead));

            // Get the rest of the data.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        else
        {
            // Signal that all bytes have been received.
            receiveDone.Set();
        }
    }

    private static void SendCallback(IAsyncResult ar)
    {
        // Retrieve the socket from the state object.
        Socket client = (Socket)ar.AsyncState;

        // Complete sending the data to the remote device.
        int bytesSent = client.EndSend(ar);
        _log.DebugFormat("Sent {0} bytes to server.", bytesSent);

        // Signal that all bytes have been sent.
        sendDone.Set();
    }

    public void SendMessage(byte[] message)
    {
        _client.BeginSend(message, 0, message.Length, 0, new AsyncCallback(SendCallback), _client);
        sendDone.WaitOne();
    }

    public void Connect()
    {
        _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _client.BeginConnect(_endpoint, new AsyncCallback(ConnectCallback), _client);
        connectDone.WaitOne();

        Receive();
    }

    public void Disconnect()
    {
        try
        {
            _client.Shutdown(SocketShutdown.Both);
            _client.Close();
        }
        finally
        {
            _client = null;

            connectDone.Reset();
            sendDone.Reset();
            receiveDone.Reset();
        }
    }

    private void ReceivedNewMessage(string message)
    {
        if (this.OnReceiveMessage != null)
        {
            this.OnReceiveMessage(message);
        }
    }

    public bool IsConnected
    {
        get
        {
            if (_client == null) return false;
            return _client.Connected;
        }
    }
}

所有回调都需要处理异常,这在网络编程中相对常见


在这种情况下,可能发生的是
client.EndReceive(ar)
正在抛出ObjectDisposedException,因为调用套接字时套接字已经关闭。

静态成员和实例成员的混合使用非常麻烦。你是从多个线程中使用这个对象吗?我现在已经删除了所有的“静态”,因为它们是从我基于更改的原始代码中遗留下来的。但是仍然看到同样的问题。如果我不调用_client.Close(),应用程序就可以正常工作。当我使用这个命令时,我看到了“正在消失”的问题。我似乎已经通过在Disconnect函数中调用“shutdown”修复了这个错误。在“ReceiveCallBack”函数中,当“bytesRead”=0且我添加的标志设置为closingdown模式时,我执行其余的结束代码。正如您所描述的,我遇到了一个问题:
EndReceive
正在引发异常,我在我的
try
块中考虑了
SocketException
,而不是
ObjectDisposedException
。然而,不幸的是,像这样的aync代码中的异常对于简单的输出消息是沉默的(它们不会向上传播并在某处显示堆栈跟踪),但仍然终止了我的程序!