Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I use AsynchronousServerSocketChannel for accepting connections?

Tags:

I would like to write an asynchronous server using Java 7 and NIO 2.

But how should I use AsynchronousServerSocketChannel?

E.g. if I start with:

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

Then when I do server.accept(), the program terminates because that call is asynchronous. And if I put that code in an infinite loop, an AcceptPendingException is thrown.

Any suggestions on how to write a simple asynchronous server using AsynchronousServerSocketChannel?

Here is my full example (similar to the example in the 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();
        }
    }
}
like image 575
Jonas Avatar asked Jan 20 '12 11:01

Jonas


2 Answers

You are on the right track, calling accept() from the completed callback in order to accept more connections should work.

A simple (but ugly) way to prevent the thread from terminating is simply to loop until the thread is interrupted.

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

A cleaner way is to use AsynchronousChannelGroup. For instance:

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

You can tune how threads are handled, see the AsynchronousChannelGroup API docs for more information.

like image 113
Soulman Avatar answered Sep 21 '22 06:09

Soulman


Using asynchronous accept is useful if you have something else to do in the same thread. In you case, you are not doing something else so I would use

while(true) {
    AsynchronousSocketChannel socket = server.accept().get();
    System.out.println("Accepted " + socket);
    socket.close();
}
like image 20
Peter Lawrey Avatar answered Sep 22 '22 06:09

Peter Lawrey