Как я должен использовать AsynchronousServerSocketChannel для принятия соединений? - PullRequest
19 голосов
/ 20 января 2012

Я хотел бы написать асинхронный сервер, используя Java 7 и NIO 2.

Но как мне использовать AsynchronousServerSocketChannel?

Например, если я начну с:

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 ]

12 голосов
/ 26 февраля 2012

Вы находитесь на правильном пути, вызывая 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 .

4 голосов
/ 20 января 2012

Использование асинхронного принятия полезно, если у вас есть что-то еще в том же потоке. В вашем случае вы не занимаетесь чем-то другим, поэтому я бы использовал

while(true) {
    AsynchronousSocketChannel socket = server.accept().get();
    System.out.println("Accepted " + socket);
    socket.close();
}
1 голос
/ 18 апреля 2015

Другая альтернатива - заставить ваш основной метод ждать сигнала перед возвратом.Затем, если у вас есть какая-то внешняя команда отключения, вы просто уведомляете сигнал, и основной поток отключается.

private static final Object shutdownSignal = new Object();

public static void main(String[] args) {

    ...

    synchronized (shutdownSignal) {
        try {
            shutdownSignal.wait();
        }
        catch (InterruptedException e) {
            // handle it!
        }
    }
}
0 голосов
/ 18 мая 2016

Использовать защелку обратного отсчета, как в следующем примере

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