2011-07-14 33 views
5

以下のコードはほとんど動作するようです。私がそれのインスタンスを作成し、 "接続"を呼び出す場合、すべて正常に動作します。私が「切断」を呼び出すと、時にはすべてがうまくいきます(主に、ブレークポイントを追加して関数を段階的に進めれば)。私はブレークポイントを使用しない場合、クラス(勝つフォームのアプリケーションとしてホストされている)は消えているようです(フォームはありますが)ビジュアルスタジオはまだそれが実行されていると考えています。ビジュアルスタジオの出力ウィンドウでは、 "System.ObjectDisposedException '型の例外がSystem.dllで発生しました。誰でも私が間違っていることを見つけることができますか?ソケットを閉じると非同期ソケットがクラッシュします

// 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

すべてのコールバックは、例外を処理する必要があります。これは、ネットワークプログラミングでは比較的一般的です。

この場合、おそらく、client.EndReceive(ar);が、呼び出されたときにソケットが既に閉じられているため、ObjectDisposedExceptionがスローされている可能性があります。

+0

「EndReceive」が例外を投げていて、 'ObjectDisposedException'の代わりに' try'ブロックの 'SocketException'を扱っていました。しかし、残念なのは、このような非同期コードの例外は単純な出力メッセージに沈黙していることです(スタックトレースをどこにも表示せずに**まだプログラムを終了します**)! – nh2

関連する問題