Clase TCPClient con Socket IOException solved
Artículo de Programación .Net (C# ) Clase TCPClient.
El objetivo del siguiente artículo es explicar porque es lanzada la excepcion IOException Unable to read data from the transport connection An existing connection was forcibly closed by the remote host desde la Clase TCPClient.
Lo explico debido a que estuve buscando información en diferentes webs y foros sin éxito, encontrando diversos problemas, pero no encontraba la solución ni tampoco encontraba el porque, a un problema en particular que tenía en relación a esta excepción que saltaba a veces.
Al final, debuggando y con logs, he podido dar con la solución. Y lo más importante es saber el porque daba saltaba la excepción desde el Socket Cliente (TCPClient) al hacer un Read().
Así que IOException Unable to read data from the transport connection An existing connection was forcibly closed by the remote host esta solucionado.
Ejemplo gráfico de envío y recepción sin problemas

1.- Utilizamos un Client Send común para enviar todas las peticiones, por lo que realizamos el “Send” y después el “Read and Wait response”, por lo que este canal se bloquea esperando la respuesta. Una vez recibimos la respuesta, continuamos la ejecución sin ningún problema.
Ejemplo gráfico de envío y recepción saltando la exception

” Unable to read data from the transport connection An existing connection was forcibly closed by the remote host ”
2.- Seguimos los pasos del anterior ejemplo, la diferencia es que después de realizar el “Send” y el “Read and Wait response”, durante esperamos la respuesta, ya que en ocasiones podría tardar más de lo que creemos, desde otro hilo en particulas se puede realizar otra petición que realiza un “Send” y justo cuando se prepara para el “Read and Wait response” saltará la excepción.
¡¡¡ Justo en este momento saltará la excepción del primer Read(), diciendo que no puede leer !!!
El Problema
El Problema existe cuando se utiliza un único Socket Client, compartido entre diferentes hilos o procesos pueden llegar a utilizarlo, sin su debido control para la concurrencia. No es que se estuviera utilizando de forma incorrecta el TCPClient, simplemente era un tema de colisión entre diferentes procesos accediendo al mismo canal de comunicación.
Solución
Según el caso puede variar, en función de las necesidades de cada proyecto.
1.- Cada vez que se realiza el Send, en el mismo método crear un TCPClient diferente
que realiza el Send, Read and Wait y Close and null.
2.- Crear un TCPClient para cada Hilo diferente que necesite enviar peticiones. Por lo que la colisión no existiría.
3.- Secciones criticas, y controlar el acceso concurrente.
4.- …
Gracias, y espero que sea de ayuda.
Que tal porkeno, me siguen saliendo los mismo mensajes amigo… no se ha reparado la parte de no se puede escribir datos en la conexion de transporte. una operacion de bloqueo fue interrumpida por una llamada a WSACancelBlockingCall.
Espero tus comentarios
Mira ahora el problema que tengo es que me dice que no puedo responder al cliente, esta excepcion me sale desde la clase servidor que tengo… podrías pasarme una clase servidor tcpclient que tengas implementada? lo que yo necesito es procesar la información que me envia el client y devolverle por el mismo stream los datos, pero todo esto sin que me salga la excepcion: No se puede obtener acceso al objeto eliminado. Nombre del Objeto: ‘System.Net.Sockets.NetWorkStream’
Espero tu respuesta.
Saludos!!!
@Fer, Si puedes, mándame la clase Server, Client y como usas el Client, al Correo y les echo un vistazo al Código.
Creo que el problema que te da es porque haces un client.Close() antes de tiempo. Este client.Close() puede ser que se provoque desde el cliente o desde el Servidor, por eso tengo que mirar el código.
En el Ejemplo, el Client envía y recibe UNA respuesta, si el proceso conlleva más peticiones de envíos y respuestas quizás el código debas modificarlo. Por ejemplo, en un servidor de correo, existen varias peticiones de envío y respuesta antes de finalizar la conexión, en este caso el ejemplo no serviría. Por eso, me interesaría el código y algún ejemplo de comunicación que podrían llegar a tener entre el cliente y el servidor.
Espero ser de ayuda.
Que tal porkeno, muchas gracias por la respuesta… efectivamente habia un close del lado del servidor, lo que al parecer eso ocasionaba la excepcion, sin embargo voy a seguir testeando mi aplicación a ver si no encuentro otro error, de ser así te enviaría mi código.
Pero de todas formas muchas gracias por la pronta respuesta.
Saludos!!!
@Fer, de nada. Me alegra saber que soy de ayuda.
que tal porkeno, aquí de nueva cuenta…. mira tengo una duda, implemente tu código a mis necesidades, sin embargo al realizar la concurrencia el servidor le devuelve a varios clientes lo mismo que que habia pedido x Cliente, yo solo utilizo tu clase Client and MyListen. sin embargo es necesario usar la clase ClientManager para manejar la concurrencia?? o también con el evento y el autoreset de la clase Client se manejaría??
Saluidos!!!
@Fer, buenas.
El ClientManager es como un “Wrapper” para evitar la Excepción del Post. Lo de la concurrencia no se arregla con eso. La concurrencia la maneja el Servidor.
Puede estar pasándote dos cosas.
1.- El servidor no maneja bien la concurrencia y envía el mismo mensaje (el último) a todos los clientes
2.- En el lado Cliente, cuando recibes el mensaje, lo almacenas en una variable que reutilizas entre todos los clientes, como no se gestiona bien, se machaca la información recibida por el servidor creando la sensación de que el servidor siempre envía lo mismo, pero es en la parte cliente donde se crea esa sensación.
Espero ser de ayuda.
Pues si, estaré verificando esas 2 partes y la parte que me suena más es el servidor concurrente que no funciona bien.
Tendrías por allá una aplicación de servidor concurrente? si serías tan amable proporcionarmela o mostrarme una manera de hacer un servidor concurrente.
Saludos y espero tu respuesta…
@Fer, Miraré de ayudarte.
Saludos
Que tal @Porkeno, ya le he hecho unos cambios al código para que al momento de que se conecte un cliente pueda yo realizar una operacion. sin embargo tengo un pequeño in conveniente.
Yo tengo una clase principal que se encuentra conectado a un servidor externo que me devuelve datos, y en esa clase principal yo lanzo el servidor para una comunicación local con muchos clioentes que me mandan peticiones…. entonces yo recibo esas peticiones en la clase TCPServerBaseImplementada y las envio al servidor externo mediante mi clase PrincipalEnviaServidorEsperaRespuesta, luego espero la respuesta y con la misma le devuelvo a TCPServerBaseImplementada para que esta por medio de la función SendData la envie al cliente que me hizo la solicitud.
El problema es que nop puedo pasar la clse ConnectionThread a la clase PrincipalEnviaServidorEsperaRespuesta… que me recomendarás?? implementar CLIENTE del servidor externo y SERVIDOR de mis peticiones entrantes en la misma clase???
Espero me halla dado a entender y puedas apoyarme con esta duda