Pregunta

Al escribir un código de prueba, descubrí que Selector.select () puede regresar sin Selector.selectedKeys () que contiene claves para procesar. Esto está sucediendo en un bucle cerrado cuando registro un canal accept () ed con

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

como las operaciones de interés.

Según los documentos, select () debería volver cuando:

1) Hay canales sobre los que se puede actuar.

2) Llamas explícitamente a Selector.wakeup () - no hay teclas seleccionadas.

3) Usted explícitamente Thread.interrupt () el hilo haciendo el select () - no hay teclas seleccionadas.

Si no obtengo claves después de seleccionar (), debo estar en los casos (2) y (3). Sin embargo, mi código no está llamando a wakeup () o interrupt () para iniciar estos retornos.

¿Alguna idea de qué está causando este comportamiento?

¿Fue útil?

Solución

Respuesta corta: elimine OP_CONNECT de la lista de operaciones que le interesan para la conexión aceptada; una conexión aceptada ya está conectada.

Logré reproducir el problema, que podría ser exactamente lo que te está sucediendo:

import java.net.*;
import java.nio.channels.*;


public class MyNioServer {
  public static void main(String[] params) throws Exception {
    final ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.configureBlocking(true);
    serverChannel.socket().bind(new InetSocketAddress("localhost", 12345));
    System.out.println("Listening for incoming connections");
    final SocketChannel clientChannel = serverChannel.accept();
    System.out.println("Accepted connection: " + clientChannel);


    final Selector selector = Selector.open();
    clientChannel.configureBlocking(false);
    final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT);
    System.out.println("Selecting...");
    System.out.println(selector.select());
    System.out.println(selector.selectedKeys().size());
    System.out.println(clientKey.readyOps());
  }
}

Después de que el servidor anterior recibe una conexión, el primer select () en la conexión sale sin bloqueo y no hay teclas con operaciones listas. No sé por qué Java se comporta de esta manera, pero parece que muchas personas son mordidas por este comportamiento.

El resultado es el mismo en Sun's JVM 1.5.0_06 en Windows XP, así como en Sun's JVM 1.5.0_05 y 1.4.2_04 en Linux 2.6.

Otros consejos

La razón es que OP_CONNECT y OP_WRITE son lo mismo bajo el capó, por lo que nunca debe estar registrado para ambos simultáneamente (ídem OP_ACCEPT y OP_READ ), y nunca debe estar registrado para OP_CONNECT cuando el canal ya está conectado, como en este caso, después de haber sido aceptado.

Y OP_WRITE casi siempre está listo, excepto cuando el buffer de envío del socket en e kernel está lleno, por lo que solo debe registrarse para eso después de obtener una escritura de longitud cero. Entonces, al registrar el canal ya conectado para OP_CONNECT, realmente se estaba registrando para OP_WRITE, que estaba listo, por lo que select () se activó.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top