2012-01-20 10 views
18

Chciałbym napisać serwer asynchroniczny używając Java 7 i NIO 2.Jak używać AsynchronousServerSocketChannel do akceptowania połączeń?

Ale jak mam korzystać z AsynchronousServerSocketChannel?

E.g. jeśli zacznę:

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

Wtedy kiedy ja server.accept() program kończy dlatego, że połączenie jest asynchroniczny. A jeśli wstawię ten kod w nieskończoną pętlę, zostanie zgłoszony AcceptPendingException.

Wszelkie sugestie, jak napisać prosty serwer asynchroniczny za pomocą AsynchronousServerSocketChannel?

Oto mój pełny przykład (podobny do przykładu w 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

Można użyć Netty ramy, która jest specjalnie dla aplikacji klient-serwer. Używa również java NIO. Jest to łatwy i szybki rozwój serwera. przejdź przez http://netty.io/ –

+3

@Optimus: Wiem o netty, ale to nie ma znaczenia dla tego pytania. – Jonas

Odpowiedz

9

jesteś na właściwej drodze, nazywając accept() z wypełnionym zwrotnego, aby przyjąć więcej połączeń powinno działać.

Prostym (ale brzydkim) sposobem zapobiegania kończeniu się nici jest po prostu pętla, dopóki wątek nie zostanie przerwany.

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

Czystszy sposób to użycie AsynchronousChannelGroup. Na przykład:

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); 

Można dostroić jak nici są obsługiwane, patrz AsynchronousChannelGroup API docs aby uzyskać więcej informacji.

+4

'// tak, sen() jest zły, ale czasami mnie to nie obchodzi" Powinieneś się tym przejmować. –

+4

Heh. Nie przejmuj się tym, prawdopodobnie z powodu wywołania sleep(), mimo że nazwałem je _ugly_ i _evil_, a następnie zademonstrowałem ładniejszy sposób. Wydaje się to dość dogmatyczne. :-) – Soulman

3

Korzystanie asynchroniczny zaakceptować to przydatne, jeśli masz coś innego do zrobienia w tym samym wątku. W Tobie przypadku nie robią coś innego, więc chciałbym użyć

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

Future.get() czeka ... –

+0

@gnarly To robi, ale accept() zwraca inną przyszłość za każdym razem. –

+0

Moim celem jest twój serwer blokujący, który pokonuje cel ['AsynchronousServerSocketChannel'] (http://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousServerSocketChannel.html) . –

2

Inną alternatywą jest posiadanie głównej metody oczekiwania na sygnał przed powrotem. Następnie, jeśli masz jakieś zewnętrzne polecenie wyłączenia, po prostu powiadamiasz sygnał i główny wątek zostaje wyłączony.

private static final Object shutdownSignal = new Object(); 

public static void main(String[] args) { 

    ... 

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

liczyć Wykorzystanie w dół zatrzask jak w poniższym przykładzie

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(); 
    } 
Powiązane problemy