2012-01-20 17 views
18

Java 7とNIO 2を使用して非同期サーバーを作成したいと考えています。AsynchronousServerSocketChannelを使用して接続を受け入れる方法を教えてください。

AsynchronousServerSocketChannelはどうすればよいですか?

など。私はで始まる場合:私はserver.accept()を行うときに呼び出しが非同期あるので

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

はその後、プログラムを終了します。そしてそのコードを無限ループに入れると、AcceptPendingExceptionがスローされます。

AsynchronousServerSocketChannelを使用して単純な非同期サーバーを作成する方法に関する提案はありますか?ここで

は、(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

をカウントダウン。また、Java NIOも使用します。それはサーバーの簡単で迅速な開発です。 –

+3

@Optimus:私はネチェットについて知っていますが、それはこの質問には関係ありません。 – Jonas

答えて

9

を使用する他の何かをやっていません。

スレッドが終了しないように単純な(しかし醜い)方法は、スレッドが中断されるまでループすることです。

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

AsynchronousChannelGroupを使用するのがよりクリーンな方法です。例えば:

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

あなたはチューニングのスレッドがどのように扱われるか、詳細についてはAsynchronousChannelGroup API docsを見ることができます。

+4

'//はい、sleep()は悪ですが、時には気にしません。気をつけてください。 –

+4

Heh。私はそれを_ugly_と_evil_と呼んでも、おそらくsleep()呼び出しのために、これをダウンホートしておきましょう。それはかなり独断的なようだ。 :-) – Soulman

3

非同期が受け入れる使用あなたが同じスレッドで行うには何か他のものを持っている場合に便利です。あなたのケースでは、動作するはずですより多くの接続を受け入れるために完了コールバックからaccept()を呼び出して、私はあなたが正しい軌道に乗っている

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

Future.get()が... –

+0

@gnarlyを待ちますが、accept()は毎回別のFutureを返します。 –

+0

あなたの例はブロッキング・サーバーです。これは['AsynchronousServerSocketChannel'](http://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousServerSocketChannel.html)の目的に反するものです。 。 –

2

もう1つの方法は、メインメソッドがシグナルを待ってから戻ることです。次に、何らかの外部シャットダウンコマンドがある場合は、シグナルだけを通知し、メインスレッドはシャットダウンします。

private static final Object shutdownSignal = new Object(); 

public static void main(String[] args) { 

    ... 

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

使用あなたは、クライアント・サーバ・アプリケーションのために特別であるネッティーフレームワークを使用することができ、ラッチ、次の例のように

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