关闭套接字时异步套接字崩溃

时间:2011-07-14 15:41:09

标签: c# sockets

下面显示的代码几乎可以正常工作。如果我创建它的实例并调用“连接”,一切正常。当我调用“Disconnect”时,有时一切都很好(主要是如果我添加一个断点并慢慢地逐步执行该功能)。如果我不使用断点,那么类(作为win表单应用程序托管)似乎消失了(表单确实如此)但是visual studio仍然认为它正在运行。在visual studio的输出窗口中,我得到“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;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

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

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