2011-07-14 154 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