2011-08-17 8 views
5

Ho implementato un sistema che simula l'evento DataReceived di una porta seriale, per cui la lettura dei dati dal NetworkStream di un oggetto TCPClient viene attivata utilizzando il metodo BeginRead() come segue:Chiusura di un NetworkStream dopo aver chiamato BeginRead() in C#

TcpClient server = new TcpClient(); 
server.Connect(IPAddress.Parse(ip), 10001); 
server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), server.GetStream()); 

che chiama il metodo seguente da un altro thread:

private void DataReceived(IAsyncResult result) 
    { 
     res = result; 
     server.GetStream().EndRead(result); 

     //append received data to the string buffer 
     stringBuffer += System.Text.ASCIIEncoding.ASCII.GetString(buffer); 

     //clear the byte array 
     Array.Clear(buffer, 0, buffer.Length); 

     //trigger the parser 
     waitHandle.Set(); 

     server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), buffer); 
    } 

Ciò sembra funzionare correttamente. Posso inviare e ricevere dati su un dispositivo sulla rete senza problemi. Tuttavia, quando si tenta di disconnettere utilizzando il seguente metodo, il programma si blocca:

public override void disconnect() 
{ 
    server.Close(); 
} 

Esso genera il seguente errore:

A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll 

Ho anche provato l'attuazione del metodo disconnessione come segue:

server.GetStream().Close(); 

, ma il risultato è il seguente errore:

A first chance exception of type 'System.InvalidOperationException' occurred in System.dll 

Presumo che questo abbia qualcosa a che fare con il fatto che è stato chiamato il metodo BeginRead() e il metodo EndRead() no. In questo caso, come posso chiudere lo stream senza che si blocchi?

+1

È necessario utilizzare un blocco try attorno alla chiamata EndRead() in modo da poter rilevare ObjectDisposedException. È un indicatore affidabile che la presa si è chiusa in modo imprevisto. –

+1

Ho trovato il problema. Stavo ricevendo un '' System.ObjectDisposedException'' perché le chiamate al metodo EndRead() e BeginRead() non erano circondate da blocchi try/catch. Quando ho chiuso lo stream, questi metodi stavano tentando di eseguire su un oggetto che non esisteva più. – isometrik

+0

Controlla queste risposte, la loro è la stessa domanda: http://stackoverflow.com/questions/43096943/how-to-stop-reading-from-networkstream/43101953#comment73305491_43101953 –

risposta

1

Vorrei chiamare solo GetStream una sola volta e memorizzare il risultato da qualche parte e usarlo per accedere al flusso.

Stream nstrm = server.GetStream(); 

Usa nstrm per tutti gli accessi alla NetworkStream ...

modo più sicuro sarebbe quella di mantenere una bandiera per la chiusura verso il basso e solo impostando quella bandiera in disconnect().

In DataReceived si sarebbe subito dopo EndRead controllo per quella bandiera e se è impostato fare questo:

server.Close(); 
nstrm.Close(); 

vedere http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.getstream.aspx

EDIT - come da commento:

if (flag2Close) 
{ 
    server.Close(); 
    nstrm.Close(); 
    flag2Close = false; 
} 
else 
{ 
    nstrm.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), buffer); 
} 

BTW: per il codice di produzione è necessaria una gestione delle eccezioni, ecc.

+0

Funziona, tuttavia poiché il flag è controllato dopo EndRead() viene chiamato, i dati devono essere ricevuti prima che la connessione possa essere interrotta. Quindi, se dovessi connetterti, disconnetterti, quindi riconnetterti, genererebbe un errore perché la connessione non è mai stata chiusa.Se dovessi connetterti, disconnetterti, inviare alcuni dati, quindi riconnetterli funzionerebbe. – isometrik

+0

Non sono sicuro di aver capito ... il punto in cui gestisci il flag per chiudere il TcpClient e lo Stream è totalmente a tua disposizione - potresti persino mettere il controllo direttamente prima del prossimo BeginRead e solo fare BeginRead IF the flag è falso ... vedi la mia modifica sopra – Yahia

+0

Sì, ma quando viene chiamato il metodo BeginRead(), richiama il metodo DataReceived e blocca fino a quando i dati non vengono ricevuti. Ciò significa che il flag non verrà controllato fino alla successiva iterazione del metodo, che si verifica quando i dati vengono ricevuti. – isometrik