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.
Tambien puedes dirigirte a






hola, pues que bien tu analisis, pero tengo otra duda yo me conecto con una pda y el puerto que uso para enviar es el 1500 y me conecto a ese mismo para recibir, pero si creo tcpclient para cada pda??? no se como aplicaria en mi caso
Using@melisa, Según entiendo la pda tiene que tener un tcpclient que se conecta al puerto 1500 que tendrá un tcpserver. en principio puedes tener varias pdas conectadas al puerto 1500, es el tcpserver quien por cada conexión debe ofrecer una contestación. No te entiendo muy bien, cual es el problema, o si simplemente es una duda, pero podrías poder conectarte con diferentes clientes (pda con tcpclient) a un mismo servidor que este escuchando por el puerto 1500. Es el servidor quien debería ofrecer servicio a todos los clientes correctamente. ¿Cual es tu problema? ¿te salta la excepción? y si es así ¿donde? ¿en el lado del cliente o el lado del servidor?
Usinghola… mira resulta que yo me conecto a una pc que es el servidor y ella tiene el TcpServer yo pienso puesto que tiene instalado el openfire… entonces yo conecto una pda al puerto 1500 y dejo la informacion, para que la lea la otra pda que conecte tambien al puerto 1500…y la pda que deja la informacion hace todo bien y se desconecta…pero la que debe leer, al momento de hacer el “read()” me salta la exception…
TcpClient tc = new TcpClient(host, 1500);
UsingNetworkStream ns = tc.GetStream();
FileInfo file = new FileInfo(fn);
FileStream fs = new FileStream(file.Name, FileMode.Create, FileAccess.Write);
BinaryWriter stream = new BinaryWriter(fs);
BinaryReader r = new BinaryReader(ns);
byte[] buffer = new byte[1024];
int bytesRead;
while((bytesRead = r.Read(buffer, 0, buffer.Length))!= 0)
{
stream.Write(buffer, 0, bytesRead);
}
@Melinda, intentaré contestarte esta tarde cuando llegue a casa.
Using@Melinda, Yo tengo una clase llamada SocketManager y luego otra Clase Client y otra Clase Server, La cual cada una encapsula a los objetos TCPClient y TCPListener.
Te paso un link que enlaza a un clase que contiene lo relacionado con la parte del TCPClient o la comunicación del Socket desde el lado del cliente. De esta manera podrás ver como lo tengo echo. Si hay algo que no entiendes me dices, pero estoy seguro que puedes encontrar ayuda en el MSDN de Microsoft, pero lo dicho si quieres comentarme algo aquí estamos.
SocketManagerClient
En definitiva la clase contiene un
- ClientManager // Quien nos abstrae de la complejidad de los sockets.
- Client // Crea el TCPClient, Envia y gestiona la contestación desde el Server
- MyListen // Quien recibe la información y se la pasa al Client
En Resumen, Cada vez que se envia se crea un TCPClient, y se envia la información, justo en ese momento nos esperamos a la respuesta (MyListen). Al finalizar se libera el Client. Hasta que no se recibe la respuesta el flujo de enviar no acaba. Como cada vez que se envia se crea un nuevo TCPClient no hay problema de que se solape información y que salte la excepción.
Ya me dirás Algo.
Usinggracias!!! creo que ya quedo ya quedo
Using@Melisa, pues en principio ya esta, Me imagino que he podido ayudarte, así que me alegro mucho. Saludos.
Usinghola…veo que tenia problemas con el molesto error “IOException: unable to read data from transported connection.–>System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host”..y yo tambien lo tengo.
Usingresulta que yo estoy transfiriendo informacion de una pda a otra, a las dos las conecto a un servidor openfire, atravez del tcpclient cambie mi puerto de conexion al 1500, como Melisa…la pda que envia el archivo termina su proceso normalmente…pero la que recibe me bota la ioexception, entonces sabe alguno como puedo verificar si el openfire es el que esta haciendo las cosas mal….que clase es la que debo revisar????
gracias
@Mary, a Melissa le puse un código en el comentario #5, en principio le ha ido bien. Así es como, mas o menos, tengo el TCPClient programado y me funciona. échale un vistazo y mira a ver si te sirve, parece que Melissa tenía el mismo problema o uno similar a ti, así que quizás te funcione.
UsingSaludos.
hola, estoy revisando el codigo…i surge una pregunta de que libreria sale el OnReceivedData, System.net.sockets?… es que no lo reconoce
Usingque framework necesito tener???
Using@Mary, El framework que se utiliza es el 2.0, pero el OnReceivedData es un delegado que se crea, para después publicar el evento. Me parece que tuve un descuido, ya que modifique el nombre del delegado. Prueba de poner “OnClientReceivedData” en lugar del otro. Este delegado si que lo tienes declarado.
UsingSi te va por favor avísame que me dará mucha ilusión.
Saludos y Gracias.
hola…oye pues si se arreglo el problema…pero tengo una pregunta mas….como es la transferencia de los datos???…el tcpclien se conecta al dispositivo que envia, o se hace atraves del puerto del servidor…donde ambas pda’s se conectan al mismo puerto y una deja la info y la otra la recoge???
Using@Mary, realmente depende de como trate el server a los clientes que se les conecta. Lo habitual es que el Server este escuchando por el puerto 1500 (en este caso), pero para cada cliente este abre un canal propio en otro puerto que asigna automáticamente. Dos clientes no podrán transferir nunca por el mismo canal, así que deberá asignar un canal para cada uno o sino realizar un control mediante secciones críticas o semáforos para evitar colisiones.
No se muy bien como funciona lo que estáis haciendo de las Pda’s, pero me imagino que una pda (cliente) envía un mensaje o petición (en definitiva són datos), y el server en función de lo que recibe te devuelve una contestación acorde a los datos recibidos por el cliente. Es posible que un cliente actualice información en el server, y una vez estén actualizados, el server pueda proporcionar dicha información al resto de clientes que la soliciten.
Espero haberte ayudado. Saludos.
Usingaahhh ok ahora entiendo…si eso es lo que me provocaba conflicto…bueno creo que con esto ya queda …gracias de verdad por tu tiempo y ayuda.
(desde Mexico) Mary
Using