Avatar billede dsj Nybegynder
02. juli 2003 - 00:21 Der er 1 løsning

NIO: Selector stopper block i select()

Jeg har et "sjovt" problem med Selector. Min multiplayer-server anvender multiplexed, non-blocking I/O med NIO - og følgende metode start() køres af en single-instance tråd. En anden tråd en Selector'ens accepterer inkommende klienter.

Hvis jeg connecter 50 klienter (eller bare 10) går al kommunikation perfekt, men knap 1 sekund efter klienterne disconnecter (på samme tid), begynder Selector'en at loope (blokkerer ikke længere i select()) og bruger derfor 100% CPU. De følgende linier printes derfor kontinuerligt til konsollen og fylder 20 mb i log-filen på under 10 sekunder:

* Selector: out of select(30000)
* Selector: continue

private void start() {
  Log.echoSystem("ClientHandler: started");
  try {
    selector = Selector.open();
    int keysAdded;
    while (noStopRequested) {
      SelectionKey key = null;
      try {
        keysAdded = selector.select(30000);
        System.out.println("  * Selector: out of select(30000)");

        while (!pendingQueue.isEmpty() && handleConnections) {
          SocketChannel channel = (SocketChannel)pendingQueue.remove();
          SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
          Client client = new Client(...);
          clientKey.attach(client);
        }

        if (keysAdded == 0) {
          System.out.println("  * Selector: continue");
          continue;
        }

        Set readyKeys = selector.selectedKeys();
        Iterator i = readyKeys.iterator();

        while (i.hasNext()) {
          try {
            key = (SelectionKey)i.next();
            i.remove();

            if (!key.isValid())
              Log.echoDebug(" * Selector: Key has been validated, but is being processed");

            if (key.isReadable()) {
              Client c = (Client)key.attachment();
              Log.echoDebug("  * Selector: Readable: "+c.getClientID());
              key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
              ClientWorker worker = (ClientWorker)pool.getWorker();
              worker.process(key);

            } else if (key.isWritable()) {
              Client c = (Client)key.attachment();
              Log.echoDebug("  * Selector: Writable: "+c.getClientID());
              key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
              ClientWorker worker = (ClientWorker)pool.getWorker();
              worker.process(key);

            } else {
              Log.echoDebug(" * Selector: Noticed, but key either readable nor writable");
            }
          } catch (CancelledKeyException cke) {
            Client client = (Client)key.attachment();
            if (client != null)
              client.disconnect(cke.getMessage());
          }
        }
      } catch (CancelledKeyException cke) {
        if (key != null) {
          Client client = (Client)key.attachment();
          if (client != null)
            client.disconnect(cke.getMessage());
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    try {
      selector.close();
    } catch (IOException ioe) {/* Ignore */}
  }
  Log.echoSystem("ClientHandler: stopped");
}

Denne metode Client.disconnct(String reason) anvendes til at disconnecte klienter med.

public void disconnect(String reason) {
  synchronized(closeLock) {
    if (connected) {
      connected = false;
      ...
      try {
        if (key != null) {
          key.cancel();
          if (key.selector().isOpen())
            key.selector().wakeup();
        }
      } catch (Exception e) { e.printStackTrace(); }
      try {
        channel().socket().close();
      } catch (Exception e) { e.printStackTrace(); }
    }
  }
}

Nogen der ved hvordan problemet løses??
Avatar billede dsj Nybegynder
13. juli 2003 - 18:40 #1
Problem løst: kort fortalt var problemet at key's tilknyttede channels af en eller anden grund kan risikere at blive lukket mens key'ens interest-ops er 0. Det resulterer i, at nøglen forbliver valid, men selvom den tilhørende channel er lukket og der ingen interesser er tilknyttet. Det får åbenbart selector'en til at gå ud af blok.

Hvis yderligere forklaring ønskes må man sige til - det er lidt en længere søforklaring...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester