recibir multiples examples enviar datos datagrama creación concepto con clientes java sockets

multiples - sockets java examples



Comprobando si un ClientSocket se ha desconectado en java cuelga (3)

Este es un seguimiento de:

esta pregunta

Básicamente, tengo un bucle de servidor que administra una conexión con un cliente solitario. En un punto del ciclo, si existe un ClientSocket, intenta leer para verificar si el cliente todavía está conectado:

if (bufferedReader.read()==-1 ) { logger.info("CONNECTION TERMINATED!"); clientSocket.close(); setUpSocket(); //sets up the server to reconnect to the client }else{ sendHeartBeat(); //Send a heartbeat to the client }

El problema es que, una vez que se ha creado un socket, la aplicación se cuelga de la lectura, supongo que se esperan datos que nunca llegarán, ya que el cliente nunca los envía al servidor. Antes de que esto estuviera bien, porque esta maneja correctamente se desconecta (la lectura eventualmente fallaría cuando el cliente se desconecta) y el ciclo intentaría restablecer la conexión. Sin embargo, ahora he agregado el método sendHeartBeat () anterior, que periódicamente le informa al cliente que el servidor aún está activo. Si la lectura está sosteniendo el hilo, ¡entonces los latidos del corazón nunca sucederán!

Entonces, supongo que estoy probando si la conexión aún no está funcionando correctamente. Podría, como un truco rápido, ejecutar el bufferReader.read () en un hilo separado, pero luego tendré todo tipo de problemas de concurrencia con los que realmente no quiero lidiar.

Entonces, la pregunta es un poco: 1) ¿Estoy revisando correctamente la desconexión del cliente? 2) Si no, ¿cómo debería hacerlo? 3) Si lo estoy haciendo correctamente, ¿cómo puedo obtener la lectura para no mantener el proceso como rehén? ¿O está enhebrando de la única manera?


Cuando crees tu socket, primero establece un tiempo de espera:

private int timeout = 10000; private int maxTimeout = 25000; clientSocket.setSoTimeout(timeout);

Con esto, si se agota el tiempo de espera de lectura obtendrás java.net.SocketTimeoutException (que debes atrapar). Por lo tanto, podría hacer algo como esto, suponiendo que haya establecido previamente SO_TIMEOUT como se muestra arriba, y suponiendo que el latido siempre recibirá una respuesta del sistema remoto:

volatile long lastReadTime; try { bufferedReader.read(); lastReadTime = System.currentTimeMillis(); } catch (SocketTimeoutException e) { if (!isConnectionAlive()) { logger.info("CONNECTION TERMINATED!"); clientSocket.close(); setUpSocket(); //sets up the server to reconnect to the client } else { sendHeartBeat(); //Send a heartbeat to the client } } public boolean isConnectionAlive() { return System.currentTimeMillis() - lastReadTime < maxTimeout; }

Una forma común de manejar esto es establecer el tiempo de espera en un número (digamos 10 segundos) y luego mantener un registro de la última vez que leyó con éxito desde el socket. Si han transcurrido 2.5 veces el tiempo de espera, abandone el cliente y cierre el socket (enviando así un paquete FIN al otro lado, por las dudas).

Si el latido del corazón no obtiene ninguna respuesta del sistema remoto, pero es solo una forma de generar una IOException antes cuando la conexión se ha caído, puede hacerlo (suponiendo que el sendHeartBeat en sí no arroje una IOException):

try { if (bufferedReader.read() == -1) { logger.info("CONNECTION TERMINATED with EOF!"); resetConnection(); } } catch (SocketTimeoutException e) { // This just means our read timed out ... the socket is still good sendHeartBeat(); //Send a heartbeat to the client } catch (IOException e) { logger.info("CONNECTION TERMINATED with Exception " + e.getMessage()); resetConnection(); } .... private void resetConnection() { clientSocket.close(); setUpSocket(); //sets up the server to reconnect to the client }


Debe agregar la comprobación de errores en su detección de desconexión. A veces, se puede lanzar una IOException cuando se pierde la conexión con el otro extremo.

Me temo que enhebrar es inevitable aquí. Si no desea bloquear la ejecución de su código, debe crear un hilo separado.


Está comprobando correctamente, puede agregar una captura de prueba con IOException en caso de que ocurra.

Hay una manera de evitar el enhebrado, puede usar un Selector con un zócalo sin bloqueo.

public void initialize(){ //create selector Selector selector = Selector.open(); ServerSocketChannel acceptSocket = ServerSocketChannel.open(); acceptSocket.configureBlocking(false); String bindIp = "127.0.0.1"; int bindPort = 80; acceptSocket.socket().bind(new InetSocketAddress(bindIp, bindPort)); //register socket in selector for ACCEPT operation acceptSocket.register(selector, SelectionKey.OP_ACCEPT); this.selector = selector; this.serverSocketChannel = serverSocketChannel; } public void serverStuff() { selector.select(maxMillisecondsToWait); Set<SelectionKey> selectedKeys = selector.selectedKeys(); if( selectedKeys.size() > 0 ) { if( key.isAcceptable() ){ //you can accept a new connection SocketChannel clientSk = serverSocketChannel.accept(); clientSk.configureBlocking(false); //register your SocketChannel in the selector for READ operations clientSk.register(selector, SelectionKey.OP_READ); } else if( key.isReadable() ){ //you can read from your socket. //it will return you -1 if the connection has been closed } } if( shouldSendHeartBeat() ){ SendHeartBeat } }