2011-07-14 3 views
5

Le code ci-dessous semble presque fonctionner. Si je crée une instance de celui-ci et appelez "Connect" tout fonctionne très bien. Quand j'appelle "Déconnecter", parfois tout va bien (surtout si j'ajoute un point d'arrêt et que je parcours lentement la fonction). Si je n'utilise pas de point d'arrêt, la classe (hébergée en tant qu'application win forms) semble disparaître (la forme le fait) mais Visual Studio pense toujours qu'elle fonctionne. Dans la fenêtre de sortie de Visual Studio, je reçois "Une exception de première chance de type" System.ObjectDisposedException "s'est produite dans System.dll". Quelqu'un peut-il repérer ce que je fais mal? Tous vos rappels ont besoin de gérer les exceptions, qui sont relativement communes dans la programmation de réseau.Le socket asynchrone se bloque lorsque je ferme le socket

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

Votre utilisation mixte de membres statiques et d'instances est plutôt troublante. Utilisez-vous cet objet à partir de plusieurs threads? – ChaosPandion

+0

J'ai maintenant enlevé tous les "statiques" car ceux-ci restaient du code original sur lequel mes changements étaient basés. Toujours voir le même problème cependant. – Retrocoder

+0

Si je n'appelle pas _client.Close(), l'application fonctionne correctement. Dès que j'utilise cette commande, je vois le problème "Disappearing". – Retrocoder

Répondre

1

Dans ce cas, il est probable que client.EndReceive(ar); lève une exception ObjectDisposedException car le socket est déjà fermé lorsqu'il est appelé.

+0

J'ai eu un problème comme vous le décrivez: 'EndReceive' lançait une exception, et je comptabilisais' SocketException' dans mon bloc 'try' au lieu de' ObjectDisposedException'. Cependant, ce qui est regrettable, c'est que les exceptions dans un code aync comme celui-ci sont réduites à de simples messages de sortie (elles ne se propagent pas et affichent une trace de pile quelque part) mais ** terminent toujours mon programme **! – nh2

Questions connexes