我应该如何使用AsynchronousServerSocketChannel接受连接?

时间:2012-01-20 11:31:23

标签: java asynchronous nio java-7

我想使用Java 7和NIO 2编写异步服务器。

但我应该如何使用AsynchronousServerSocketChannel

E.g。如果我开始:

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

然后当我执行server.accept()时,程序终止,因为该调用是异步。如果我将该代码置于无限循环中,则抛出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();
        }
    }
}

4 个答案:

答案 0 :(得分:12)

你在正确的轨道上,从已完成的回调中调用accept()以接受更多应该正常工作的连接。

一种简单(但丑陋)的方法来阻止线程终止只是循环直到线程被中断。

// 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

答案 1 :(得分:4)

如果您在同一个线程中还有其他事情要做,那么使用异步接受非常有用。在你的情况下,你没有做其他事情所以我会使用

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

答案 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!
        }
    }
}

答案 3 :(得分: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();
    }