2012-01-20 11 views
18

Vorrei scrivere un server asincrono utilizzando Java 7 e NIO 2.Come dovrei usare AsynchronousServerSocketChannel per accettare le connessioni?

Ma come dovrei usare AsynchronousServerSocketChannel?

E.g. se comincio con:

final AsynchronousServerSocketChannel server = 
    AsynchronousServerSocketChannel.open().bind(
     new InetSocketAddress(port)); 

Poi quando faccio server.accept(), il programma termina perché questa chiamata è asincrona . E se inserisco quel codice in un ciclo infinito, viene lanciato un AcceptPendingException.

Qualche suggerimento su come scrivere un semplice server asincrono usando AsynchronousServerSocketChannel?

Ecco il mio esempio completo (simile all'esempio nella JavaDoc):

import java.io.IOException; 
import java.net.InetSocketAddress; 
import java.nio.channels.AsynchronousServerSocketChannel; 
import java.nio.channels.AsynchronousSocketChannel; 
import java.nio.channels.CompletionHandler; 

public class AsyncServer { 

    public static void main(String[] args) { 
     int port = 8060; 
     try { 
      final AsynchronousServerSocketChannel server = 
        AsynchronousServerSocketChannel.open().bind(
          new InetSocketAddress(port)); 

      System.out.println("Server listening on " + port); 

      server.accept("Client connection", 
        new CompletionHandler<AsynchronousSocketChannel, Object>() { 
       public void completed(AsynchronousSocketChannel ch, Object att) { 
        System.out.println("Accepted a connection"); 

        // accept the next connection 
        server.accept("Client connection", this); 

        // handle this connection 
        //TODO handle(ch); 
       } 

       public void failed(Throwable exc, Object att) { 
        System.out.println("Failed to accept connection"); 
       } 
      }); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

È possibile utilizzare quadro Netty che è specialmente per l'applicazione client-server. Utilizza anche Java NIO. È facile e veloce lo sviluppo del server. passare attraverso http://netty.io/ –

+3

@Optimus: so di netty, ma non è rilevante per questa domanda. – Jonas

risposta

9

Siete sulla strada giusta, chiamando accettare() dal callback completato al fine di accettare più connessioni dovrebbe funzionare.

Un modo semplice (ma brutto) di impedire la terminazione del thread è semplicemente eseguire il ciclo finché il thread non viene interrotto.

// yes, sleep() is evil, but sometimes I don't care 
while (true) { 
    Thread.sleep(1000); 
} 

Un modo più semplice è utilizzare AsynchronousChannelGroup. Per esempio:

AsynchronousChannelGroup group = AsynchronousChannelGroup.withThreadPool(Executors 
      .newSingleThreadExecutor()); 
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group).bind(
      new InetSocketAddress(port)); 

// (insert server.accept() logic here) 

// wait until group.shutdown()/shutdownNow(), or the thread is interrupted: 
group.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); 

È possibile regolare come le discussioni vengono gestiti, vedere la AsynchronousChannelGroup API docs per ulteriori informazioni.

+4

'// sì, sleep() è malvagio, ma a volte non mi interessa 'Dovresti preoccuparti. –

+4

Heh. Continuate a scendere di quota su questo, presumibilmente a causa della chiamata a sleep(), anche se l'ho chiamata _ugly_ e _evil_, e quindi dimostrate un modo migliore. Sembra abbastanza dogmatico. :-) – Soulman

3

Uso asincrono accettare è utile se si hanno qualcos'altro da fare nello stesso thread. Nel caso si, non si sta facendo qualcosa di diverso quindi vorrei usare

while(true) { 
    AsynchronousSocketChannel socket = server.accept().get(); 
    System.out.println("Accepted " + socket); 
    socket.close(); 
} 
+0

Future.get() attende ... –

+0

@gnarly Lo fa, ma accept() restituisce un futuro diverso ogni volta. –

+0

Il mio punto è il tuo esempio è un server di blocco, che sconfigge lo scopo di ['AsynchronousServerSocketChannel'] (http://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousServerSocketChannel.html) . –

2

Un'altra alternativa è quella di avere il metodo principale in attesa su un segnale prima di tornare. Quindi, se si dispone di una sorta di comando di spegnimento esterno, basta notificare il segnale e il thread principale si arresta.

private static final Object shutdownSignal = new Object(); 

public static void main(String[] args) { 

    ... 

    synchronized (shutdownSignal) { 
     try { 
      shutdownSignal.wait(); 
     } 
     catch (InterruptedException e) { 
      // handle it! 
     } 
    } 
} 
0

contare Usa giù latch come il seguente esempio

final AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); 
    InetSocketAddress address = new InetSocketAddress(port); 
    serverChannel.bind(address); 
    final CountDownLatch latch = new CountDownLatch(1); 
    serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() { 
@Override 
     public void completed(final AsynchronousSocketChannel channel, Object attachment) { 
      serverChannel.accept(null, this); 
         } 

}); 
try { 
     latch.await(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
     Thread.currentThread().interrupt(); 
    } 
Problemi correlati