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();
}
}
}
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.
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();
}
Another alternative is to have your main method wait on a signal before returning. Then if you have some kind of external shutdown command, you just notify the signal and the main thread shuts down.
private static final Object shutdownSignal = new Object();
public static void main(String[] args) {
...
synchronized (shutdownSignal) {
try {
shutdownSignal.wait();
}
catch (InterruptedException e) {
// handle it!
}
}
}
Use count down latch like the following example
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();
}
来源:https://stackoverflow.com/questions/8940747/how-should-i-use-asynchronousserversocketchannel-for-accepting-connections