Java NIO.2 Gurus could anyone explain why this code not working when I'm commenting out the Thread.sleep(...) line.
And what is the elegant way, to tell JVM to proccess asynchronous operations until program finishes?
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class Main {
public static void main(String[] args) {
try {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("www.yahoo.com", 80),
null, new CompletionHandler<Void, Object>() {
@Override
public void completed(Void result, Object attachment) {
System.out.println("Connected");
ByteBuffer buffer = ByteBuffer.wrap("GET http://www.yahoo.com HTTP/1.1\r\n\r\n".getBytes());
channel.write(buffer, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
System.out.println("Write completed: " + result.toString());
ByteBuffer buffer = ByteBuffer.allocate(23);
channel.read(buffer, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
System.out.println("Read completed: " + result.toString());
System.out.println(new String(buffer.array()));
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
Thread.sleep(10000);
channel.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Thanks in advance.
Why it isn't working when Thread.sleep(...) is removed:
The method connect(SocketAddress remote, A attachment, CompletionHandler<Void,? super A> handler)
creates a new Thread in which he connects and invokes the handler.
So without the delay you are closing the socket before it's connected or all data was transferred.
How to avoid it
You have to find a way to wait for the other threads.
For example with java.util.concurrent.CompletableFuture<V>
:
try {
CompletableFuture<Boolean> future = new CompletableFuture<Boolean>();
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("www.yahoo.com", 80),
null, new CompletionHandler<Void, Object>() {
@Override
public void completed(Void result, Object attachment) {
System.out.println("Connected");
ByteBuffer buffer = ByteBuffer.wrap("GET http://www.yahoo.com HTTP/1.1\r\n\r\n".getBytes());
channel.write(buffer, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
System.out.println("Write completed: " + result.toString());
ByteBuffer buffer = ByteBuffer.allocate(23);
channel.read(buffer, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
System.out.println("Read completed: " + result.toString());
System.out.println(new String(buffer.array()));
//
future.complete(true);
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
//
future.complete(false);
}
});
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
//
future.complete(false);
}
});
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
//
future.complete(false);
}
});
// Wait until the other Threads are finished
System.out.println("Successs: "+future.get(10, TimeUnit.SECONDS));
channel.close();
} catch (Exception ex) {
ex.printStackTrace();
}
Or in your case you can simply handle the AsynchronousSocketChannel
this way (without the handlers):
try {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
Future<Void> futureConnect = channel.connect(new InetSocketAddress("www.yahoo.com", 80));
// wait until connected
futureConnect.get();
System.out.println("Connected");
ByteBuffer buffer = ByteBuffer.wrap("GET http://www.yahoo.com HTTP/1.1\r\n\r\n".getBytes());
Future<Integer> futureWrite = channel.write(buffer);
// wait until all data is written
Integer resultWrite = futureWrite.get();
System.out.println("Write completed: " + resultWrite.toString());
ByteBuffer bufferRead = ByteBuffer.allocate(23);
Future<Integer> futureRead = channel.read(bufferRead);
// wait ...
Integer resultRead = futureRead.get();
System.out.println("Read completed: " + resultRead.toString());
System.out.println(new String(bufferRead.array()));
// finnished now the channel can be closed
channel.close();
} catch (Exception e) {
e.printStackTrace();
}