Foros del Web » Programación para mayores de 30 ;) » Java »

Mantener socket abierto en TCP

Estas en el tema de Mantener socket abierto en TCP en el foro de Java en Foros del Web. Hola a todos! A ver si me podeis echar una mano, porque no encuentro la solución por ningún sitio. Tengo una aplicación cuyo objetivo es ...
  #1 (permalink)  
Antiguo 11/10/2011, 08:12
 
Fecha de Ingreso: noviembre-2005
Mensajes: 17
Antigüedad: 19 años
Puntos: 0
Mantener socket abierto en TCP

Hola a todos!

A ver si me podeis echar una mano, porque no encuentro la solución por ningún sitio.

Tengo una aplicación cuyo objetivo es desplegar en dos nodos y que estos nodos se comuniquen vía TCP. Me piden como requisito que el socket TCP que envía NO se cierre, pero me estoy encontrando con que si no cierro el socket en el emisor, el receptor no lo recibe.

Con un sniffer he comprobado que el mensaje llega al destino, pero por alguna razón el socket no devuelve el mensaje a mi aplicación.

Trabajo con ServerSocket y Socket. Lamentablemente, no puedo pegaros el código, pero no creo que haga falta, mi duda es conceptual ¿es obligatorio cerrar el socket en el emisor para que el receptor reciba el mensaje?

Saludos y gracias!!!
  #2 (permalink)  
Antiguo 11/10/2011, 08:41
 
Fecha de Ingreso: febrero-2011
Mensajes: 672
Antigüedad: 13 años, 10 meses
Puntos: 78
Respuesta: Mantener socket abierto en TCP

Para nada tienes que cerrar el socket para poder recibir los mensajes, eso te lo aseguro.
Debes tener algún error en la estructura de tu programa, que no libera el buffer hasta que cierras el programa........
  #3 (permalink)  
Antiguo 11/10/2011, 08:50
Avatar de chuidiang
Colaborador
 
Fecha de Ingreso: octubre-2004
Mensajes: 3.774
Antigüedad: 20 años, 2 meses
Puntos: 454
Respuesta: Mantener socket abierto en TCP

El código ayudaría, pero así, con un poco de intuición, un posible problema sea que estés leyendo el mensaje con un readline() o similar. Esto está esperando por el mensaje leyendo todos los bytes que encuentra hasta que reciba un retorno de carro. Si no recibe el retorno de carro, se queda indefinidamente a la espera.

Al cerrar el socket, se producirá un error en lectura de cierre de socket, pero posiblemente recibas lo leido hasta el momento y eso justificaría que tengas que cerrar el socket para que el otro lado reciba lo leído hasta el momento.

Y si no es readline() y retorno de carro, quizás sea que estés esperando algún tipo de caracter que haga de fin de mensaje o que tengas un bucle de lectura hasta garantizar que llegan los n bytes que componen el mensaje o cualquier variante. El socket lector no detecta el mensaje completo y se queda a la espera de lo que le falte (fin de mensaje o número de bytes). El cierre de socket hace que salga de esta espera y entregue lo leído hasta el momento.

Se bueno.
__________________
Apuntes Java
Wiki de Programación
  #4 (permalink)  
Antiguo 11/10/2011, 09:03
 
Fecha de Ingreso: noviembre-2005
Mensajes: 17
Antigüedad: 19 años
Puntos: 0
Respuesta: Mantener socket abierto en TCP

Gracias por las respuestas.

Yo pienso que el problema puede ser el que apuntas chuidiang, que el receptor espera un retorno de carro (un EOF, o lo que sea) y por eso no devuelve el mensaje.

Pienso que puede ser un tema del S.O. (Win7) porque como digo el mensaje llega al PC destino, pero serverSocket.accept(), no devuleve nada...

No he tocado a penas nada del código, no puedo mostrar más de esto, espero que sea suficiente:

Escritura
Código:
if (socket == null || socket.isClosed())	{
	socket = new Socket(ip, port);
	socket.setKeepAlive(mantenerSocket);
	output = new DataOutputStream(socket.getOutputStream());
}

XXXDatagram datagram = new XXXDatagram(sourceCountry, sourceSystem, sourceSubsystem);
datagram.setCompression(encoding);
datagram.setPriority(priority);			
byte[] bytes = datagram.encodeDatagram(message, destinationCountry, destinationSystem, destinationSubsystem);
output.write(bytes);
Lectura
Código:
Socket clientSocket = null;
DataInputStream in = null;
clientSocket = serverSocket.accept();
clientSocket.setKeepAlive(mantenerSocket);

in = new DataInputStream(clientSocket.getInputStream());
byte[] buffer = new byte[bufferSize];
byte[] datagram = new byte[bufferSize];
int numBytes = 0;
int length = 0;
while ((numBytes=in.read(buffer)) != -1)	{
	System.arraycopy(buffer, 0, datagram, length, numBytes);
	length += numBytes;
}

newDatagram(datagram);
Gracias!
  #5 (permalink)  
Antiguo 11/10/2011, 10:47
Avatar de chuidiang
Colaborador
 
Fecha de Ingreso: octubre-2004
Mensajes: 3.774
Antigüedad: 20 años, 2 meses
Puntos: 454
Respuesta: Mantener socket abierto en TCP

Hola:

accept() debe devolver un socket con el cliente que se ha conectado. Si dices que no devuelve nada, hay un problema con la conexión.
No estás usando readLine() por ningún sitio, solo write() y read(), por lo que no debería haber problemas de retornos de carro. El problema es el que te comentaba

Código java:
Ver original
  1. while ((numBytes=in.read(buffer)) != -1) {
  2. }

Ese bucle está ejecutándose hasta que ocurre un error en el socket (el -1), por lo que mientras no cierres la conexión o la rompas de alguna forma, estás leyendo (o esperando leer) y copiando en el datagram. Pero si no se cierra la conexión, en ningún momento se detecta cuándo está completo el mensaje ni se hace nada con él.

Se bueno.
__________________
Apuntes Java
Wiki de Programación
  #6 (permalink)  
Antiguo 12/10/2011, 02:24
 
Fecha de Ingreso: noviembre-2005
Mensajes: 17
Antigüedad: 19 años
Puntos: 0
Respuesta: Mantener socket abierto en TCP

Gracias por tu ayuda chuidiang

La ejecución no llega a ese bucle nunca. No puede quedarse ahí porque la ejecución no pasa del socket.accept(). Si fuera ese el problema lo hubiera visto en seguida trazando la aplicación.

Creo que por alguna razón ServerSocket no devuelve un socket y permanece bloqueado. De ahí mi duda ¿será necesario siempre cerrar el socket en el emisor para que el receptor (ServerSocket) sepa que tiene el mensaje completo y por tanto devolverlo a través del método accept()?

Saludos
  #7 (permalink)  
Antiguo 12/10/2011, 03:56
Avatar de chuidiang
Colaborador
 
Fecha de Ingreso: octubre-2004
Mensajes: 3.774
Antigüedad: 20 años, 2 meses
Puntos: 454
Respuesta: Mantener socket abierto en TCP

ServerSocket.accept() devuelve un socket cuando un cliente se le conecta. En el lado del cliente, la conexión se realiza en esta línea

socket = new Socket(ip, port);

Mira a ver si el cliente pasa por esa línea y mira si ip y port corresonden con las del servidor.

Y si no pasa del accept(), no entiendo lo de cerrar el socket. ¿Qué socket cierras?. El cliente da igual que lo cierres puesto que no se ha conectado (el servidor no sale del accept) y el del servidor no puedes cerrarlo puesto que te has quedado bloqueado en el accept().

Se bueno.
__________________
Apuntes Java
Wiki de Programación
  #8 (permalink)  
Antiguo 13/10/2011, 09:04
 
Fecha de Ingreso: noviembre-2005
Mensajes: 17
Antigüedad: 19 años
Puntos: 0
Respuesta: Mantener socket abierto en TCP

Si, el cliente pasa por esa línea. He comentado que el el cliente envía su petición sin problemas. Con un sniffer veo el paquete salir de un nodo y llegar al otro. Pero el serverSocket de Java parece que ni se entera...

Cuando cierro el socket en el cliente después de escribir, el método accept() en el servidor me devuelve un socket con el que puedo leer la petición sin problemas.
  #9 (permalink)  
Antiguo 13/10/2011, 09:40
 
Fecha de Ingreso: noviembre-2005
Mensajes: 17
Antigüedad: 19 años
Puntos: 0
Respuesta: Mantener socket abierto en TCP

Estaba equivocado chuidiang. Y bravo por ti porque habías dado en el clavo.

No estaba depurando bien el código y efectivamente la ejecución se queda en el while:

Código:
while ((numBytes=in.read(buffer)) != -1) {
Cada vez que lanzo un mensaje desde el cliente, este bucle hace una iteración, pero como nunca devuelve -1, se queda ahí.

Me estoy planteando aumentar el buffer para no necesitar el bucle (aunque no me gusta mucho esta solución (no se si podrían llegar mensajes muy grandes...) ¿Podría hacer alguna otra cosa?

Gracias chuidiang por tu ayuda!
  #10 (permalink)  
Antiguo 13/10/2011, 13:38
Avatar de chuidiang
Colaborador
 
Fecha de Ingreso: octubre-2004
Mensajes: 3.774
Antigüedad: 20 años, 2 meses
Puntos: 454
Respuesta: Mantener socket abierto en TCP

Hola:

Lo habitual en estos casos es saber el tamaño del mensaje para leer ese número de bytes, o bien esperar algún tipo de fin de mensaje, como el retorno de carro que comentábamos al principio.

Para la primera opción, por ejemplo, se suele enviar un primer entero que indica cual es el mensaje que se envía a continuación. El receptor lee el entero y sabiendo que mensaje va a recibir puede hacer la lectura del tamaño exacto.

Si los mensajes no son de longitud fija, se puede enviar un entero con la longitud del mensaje que va a continuación, así el receptor lee primero ese entero y sabe cuántos bytes tiene que leer después.

Finalmente, la otra opción es enviar el mensaje y terminarlo con un retorno de carro (byte \n). El receptor leería hasta encontrar un \n, que es el fin de mensaje.

Se bueno.
__________________
Apuntes Java
Wiki de Programación

Etiquetas: redes, sockets, tcp
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 01:03.