问题
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();
}
}
}
回答1:
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.
回答2:
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();
}
回答3:
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!
}
}
}
回答4:
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