2011-08-17 26 views
5

Implementé un sistema que imita el evento DataReceived de un puerto serie, mediante el cual la lectura de datos de un NetworkStream de un objeto TCPClient se desencadena utilizando el método BeginRead() de la siguiente manera:Cerrar un NetworkStream después de llamar a BeginRead() en C#

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

que llama al siguiente método desde otro hilo:

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); 
    } 

Esto parece funcionar correctamente. Puedo enviar y recibir datos a un dispositivo en la red sin problemas. Sin embargo, cuando intento de desconectar mediante el siguiente método, el programa se bloquea:

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

Se lanza el siguiente error:

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

También he intentado implementar el método de desconexión de la siguiente manera:

server.GetStream().Close(); 

pero esto da como resultado el siguiente error:

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

Supongo que esto tiene algo que ver con el hecho de que se ha llamado al método BeginRead() y no al método EndRead(). Si ese es el caso, ¿cómo puedo cerrar la transmisión sin que se cuelgue?

+1

Debe usar un bloque try alrededor de la llamada EndRead() para que pueda atrapar la ObjectDisposedException. Es un indicador confiable de que el socket se cerró inesperadamente. –

+1

He encontrado el problema. Estaba obteniendo una '' System.ObjectDisposedException'' porque las llamadas al método EndRead() y BeginRead() no estaban rodeadas por bloques try/catch. Cuando cerré la transmisión, estos métodos intentaban ejecutarse en un objeto que ya no existía. – isometrik

+0

Verifique estas respuestas, se trata de la misma pregunta: http://stackoverflow.com/questions/43096943/how-to-stop-reading-from-networkstream/43101953#comment73305491_43101953 –

Respuesta

1

Llamaría GetStream solo una vez y almacenaría el resultado en algún lugar y lo usaría para acceder a la transmisión.

Stream nstrm = server.GetStream(); 

Uso nstrm para todos los accesos a la NetworkStream ...

forma más segura sería mantener una bandera para el cierre hacia abajo y sólo la creación de esa bandera en disconnect().

En DataReceived usted directamente después EndRead cheque por esa bandera y si se establece hacer esto:

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

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

EDITAR - según el comentario:

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

Por cierto: para el código de producción, necesita un poco de manejo de excepciones, etc.

+0

Esto funciona, sin embargo, desde que se marca la bandera después Se llama a EndRead(), los datos deben recibirse antes de que la conexión pueda finalizar. Entonces, si tuviera que conectarme, desconectarme y luego volver a conectarme, arrojaría un error porque la conexión nunca se había cerrado.Si tuviera que conectarme, desconectarme, enviar algunos datos y luego volver a conectar, funcionaría. – isometrik

+0

No estoy muy seguro de entender ... el punto donde manejas la bandera para cerrar el TcpClient y el Stream depende totalmente de ti; incluso puedes poner el cheque directamente antes del próximo BeginRead y solo hacer el BeginRead IF the flag es falso ... ver mi edición anterior – Yahia

+0

Sí, pero cuando se llama al método BeginRead(), devuelve la llamada al método DataReceived y bloquea hasta que se reciban los datos. Esto significa que la bandera no se comprobará hasta la próxima iteración del método, que se produce cuando se reciben los datos. – isometrik

Cuestiones relacionadas