2011-07-19 17 views
5

Sto provando a connettermi al mio server con una combinazione TcpClient.BeginConnect/TcpClient.EndConnect. Tuttavia, alcune cose non funzionano come dovrebbero.TcpClient.EndConnect genera NullReferenceException quando il socket è chiuso

Lo scenario è il seguente:

  • Chiama per il TcpClient.BeginConnect
  • Server è volutamente non in linea (a scopo di test) - quindi nessun collegamento può essere fatto.
  • Chiudo l'applicazione (client.Close() viene chiamato nel processo che closes the socket which in turn stops the async operation)
  • TcpClient connessione metodo di callback accade dando IAsyncResult
  • chiamata al metodo TcpClient.EndConnect con il dato IAsyncResult
  • NullReferenceException avviene su EndConnect (?)
  • Poiché l'ultimo modulo (finestra) è stato chiuso, l'app dovrebbe uscire, tuttavia non t, almeno non fino al completamento dell'operazione BeginConnect (il che è strano, poiché la richiamata è già stata richiamata).

exception

Quello che succede qui è che un NullReferenceException e 'colto. Come puoi vedere dall'immagine sopra, né clientar sono null. Il problema è che il MSDN documentation for the EndConnect non menziona il caso in cui viene generata questa eccezione.

Quindi, in pratica, non ho idea di cosa stia succedendo. Il problema è che sono costretto ad aspettare che l'app si chiuda (come se l'operazione di connessione fosse ancora in attesa di un timeout). Se un server è online, collega e scollega semplicemente.

CosaNullReferenceExceptionin questo contesto significa? Come evitare l'operazione BeginConnect per bloccare la chiusura dell'applicazione nel caso in cui la connessione non possa essere stabilita?


Note aggiuntive (richiesto in commenti):

Ecco il codice per creare il client (client è una variabile membro:

public void Connect() 
{ 
    try 
    { 
     lock (connectionAccess) 
     { 
      if (State.IsConnectable()) 
      { 
       // Create a client 
       client = new TcpClient(); 
       client.LingerState = new LingerOption(false, 0); 
       client.NoDelay = true; 

       State = CommunicationState.Connecting; 

       client.BeginConnect(address, port, onTcpClientConnectionEstablished, null); 
      } 
      else 
      { 
       // Ignore connecting request if a connection is in a state that is not connectable 
      } 
     } 
    } 
    catch 
    { 
     Close(true); 
    } 
} 

anche il metodo close:

public void Close(bool causedByError) 
{ 
    lock (connectionAccess) 
    { 
     // Close the stream 
     if (clientStream != null) 
      clientStream.Close(); 

     // Close the gateway 
     if (client != null) 
      client.Close(); 

     // Empty the mailboxes 
     incomingMailbox.Clear(); 
     outgoingMailbox.Clear(); 

     State = causedByError ? CommunicationState.CommunicationError : CommunicationState.Disconnected; 
    } 
} 
+0

Does InnerException fornisce ulteriori informazioni su cosa fosse NULL? – Tremmors

+0

@Tremmors Nope. InnerException è nullo. Nessun aiuto da StackTrace (onTcpClientConnectionEstablished> EndConnect). :( –

+0

Sì, chiaramente un bug del framework Nel caso in cui il TcpClient venga chiuso prima che venga chiamato EndConnect(), si suppone che lanci ObjectDisposedException. Sembrerebbe ottenere NullReferenceException invece la prima o due volte, quindi inizierà a lanciare ObjectDisposedException Come previsto, ti suggerisco di gestirlo nello stesso modo in cui avresti dovuto eseguire ObjectDisposedException (cioè "timeout della connessione/errore/qualsiasi altra ragione hai chiamato Close()"). Tuttavia, non so se potrebbero esserci perdite di risorse qui dal momento che EndConnect() non sta completando Probabilmente nulla che il GC non possa gestire. :) – Tom

risposta

0

Ho avuto un errore simile e ho finito per usare questo codice. Non sono sicuro se verrà conservato con l'interfaccia IASyncResult, ma potrebbe esserci un modo simile per eseguire questo controllo. Mi accorgo che il tuo ar.AsyncState == null, quindi forse prova ad iniziare da lì, cioè è nullo quando ti connetti correttamente?

private void connConnectCompleted(AsyncCompletedEventArgs e) 
{ 
    if (e.Error != null) 
    { 
     // Something didn't work...abort captain 
     CloseSocket(); 
     Console.WriteLine(this.GetType().ToString() + @":Error connecting socket:" + e.Error.Message); 
     return; 
    } 
    // Do stuff with your connection 
} 

EDIT: Scusate, non mi rendevo conto io non postare quello che ha generato i miei AsyncCompletedEventArgs, che è più legata a quello che stai facendo. Vedrai il motivo per cui mi stavo chiedendo di ar.AsyncState è nullo.

private void OnConnect(IAsyncResult asyncResult) 
{ 
    if (OnConnectCompleted == null) return; // Check whether something is using this wrapper 
    AsyncCompletedEventArgs args; 
    try 
    { 
     Socket outSocket = (Socket) asyncResult.AsyncState; 

     // Complete connection 
     outSocket.EndConnect(asyncResult); 

     args = new AsyncCompletedEventArgs(null); 
     OnConnectCompleted(this, args); 
    } 
    catch (Exception e) 
    { 
     args = new AsyncCompletedEventArgs(e.Message); 
     OnConnectCompleted(this, args); 
    } 
} 
+0

AsyncState viene utilizzato per passare alcuni dati personalizzati al metodo di callback. Non ne ho bisogno quindi è per questo che è nullo. Non può produrre un errore. Non capisco il tuo esempio (è incompleto). IAsyncResult non ha errori e suppongo che dovresti fornire il codice per il metodo CloseSocket() poiché è il tuo metodo personalizzato. Othwerise, non so come il tuo esempio di codice possa essere utile. –

+0

CloseSocket() avvia solo un paio di eventi per notificare qualsiasi altra parte del programma, quindi esegue .Close() sul socket. – themartinmcfly

1

Il NullReferenceException è probabilmente dovuto al TcpClient.Client essere null.

Se si dovesse seguire la MSDN Example per TcpClient.BeginConnect e passare l'oggetto TcpClient come oggetto Stato:

private void onConnEst(IAsyncResult ar) 
{ 
     try 
     { 
      TcpClient client = (TcpClient)ar.AsyncState; 
      if(client!=null && client.Client!=null) 
      { 
       client.EndConnect(ar); 
      } 
     } 
     catch(Exception ex){...} 
} 

Questo dovrebbe gestire il caso in cui Close() viene chiamato prima della richiamata.

Tornando al tuo problema, quanto tempo ci vuole per chiudere l'applicazione?

+0

Perché hai lanciato ar.AsyncResult? Intendevi ar.AsyncState? Ad ogni modo, il mio cliente è un membro privato, quindi non ho bisogno di passarlo al metodo asincrono. Attualmente non sono in grado (ovvero non al lavoro) di verificare se TcpClient.Client è nullo. Tuttavia, in base alla mia memoria ed esperienza precedente, se non chiamo client.EndConnect l'applicazione si blocca ancora quando provo a chiuderla. Di solito dura come il timeout di connessione (~ 20s). E se non chiudo l'app durante il tentativo di connessione, BeginConnect fallirà dopo lo stesso tempo. –

+0

Oops: sei corretto, "ar.AsycResult' dovrebbe essere" ar.AsyncState ". Post modificato per riflettere le modifiche. – zrc210

+0

Sareste in grado di pubblicare come si costruisce il TcpClient e BeginConnect? Leghi il socket prima di BeginConnect? Inoltre, non che dovrebbe essere importante, ma quale framework .Net stai usando? – zrc210

1

Questo ovviamente un bug all'interno della classe TcpClient. Anch'io l'ho affrontato. TcpClient.Dispose può impostare il campo Client su null ma EndConnect non lo prevede.

+2

Benvenuti in SO! Potresti considerare di elaborare un po 'di più sui dettagli del bug per rendere la tua risposta un po' più approfondita per le altre persone che potrebbero venire con questa domanda. –

0

Questo è a know bug.

Si dovrebbe ricevere "ObjectDisposedException" anziché "NullReferenceException".

Problemi correlati