2011-07-14 152 views
5

下面显示的代码似乎几乎工作。如果我创建它的实例并调用“连接”,所有工作正常。当我打电话给“断开”时,有时候一切都很好(主要是当我添加一个断点并慢慢地逐步完成功能时)。如果我不使用断点,该类(作为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; 
     } 
    } 
} 
+0

您对静态和实例成员的混合使用相当麻烦。你是从多个线程使用这个对象吗? – ChaosPandion

+0

我现在已经删除了所有“静态”,因为这些都是从我的更改所基于的原始代码中遗留下来的。但仍然看到同样的问题。 – Retrocoder

+0

如果我不打电话_client.Close()应用程序正常工作。只要我使用这个命令,我就会看到“消失”的问题。 – Retrocoder

回答

1

您的回调都需要处理异常,这是在网络编程relativly常见。

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

+0

我遇到了一个问题,就像你描述的那样:'EndReceive'正在抛出一个异常,并且我在'try'块中占用'SocketException'而不是'ObjectDisposedException'。然而,不幸的是,像这样的异步代码中的异常被简单的输出消息所抑制(它们不会传播并在某处显示堆栈跟踪),但是**仍然会终止我的程序**! – nh2