IOException during blocking network NIO in JDK 1.7
- by Bass
I'm just learning NIO, and here's the short example I've written to test how a blocking NIO can be interrupted:
class TestBlockingNio {
private static final boolean INTERRUPT_VIA_THREAD_INTERRUPT = true;
/**
* Prevent the socket from being GC'ed
*/
static Socket socket;
private static SocketChannel connect(final int port) {
while (true) {
try {
final SocketChannel channel = SocketChannel.open(new InetSocketAddress(port));
channel.configureBlocking(true);
return channel;
} catch (final IOException ioe) {
try {
Thread.sleep(1000);
} catch (final InterruptedException ie) {
}
continue;
}
}
}
private static byte[] newBuffer(final int length) {
final byte buffer[] = new byte[length];
for (int i = 0; i < length; i++) {
buffer[i] = (byte) 'A';
}
return buffer;
}
public static void main(final String args[]) throws IOException, InterruptedException {
final int portNumber = 10000;
new Thread("Reader") {
public void run() {
try {
final ServerSocket serverSocket = new ServerSocket(portNumber);
socket = serverSocket.accept();
/*
* Fully ignore any input from the socket
*/
} catch (final IOException ioe) {
ioe.printStackTrace();
}
}
}.start();
final SocketChannel channel = connect(portNumber);
final Thread main = Thread.currentThread();
final Thread interruptor = new Thread("Inerruptor") {
public void run() {
System.out.println("Press Enter to interrupt I/O ");
while (true) {
try {
System.in.read();
} catch (final IOException ioe) {
ioe.printStackTrace();
}
System.out.println("Interrupting...");
if (INTERRUPT_VIA_THREAD_INTERRUPT) {
main.interrupt();
} else {
try {
channel.close();
} catch (final IOException ioe) {
System.out.println(ioe.getMessage());
}
}
}
}
};
interruptor.setDaemon(true);
interruptor.start();
final ByteBuffer buffer = ByteBuffer.allocate(32768);
int i = 0;
try {
while (true) {
buffer.clear();
buffer.put(newBuffer(buffer.capacity()));
buffer.flip();
channel.write(buffer);
System.out.print('X');
if (++i % 80 == 0) {
System.out.println();
Thread.sleep(100);
}
}
} catch (final ClosedByInterruptException cbie) {
System.out.println("Closed via Thread.interrupt()");
} catch (final AsynchronousCloseException ace) {
System.out.println("Closed via Channel.close()");
}
}
}
In the above example, I'm writing to a SocketChannel, but noone is reading from the other side, so eventually the write operation hangs.
This example works great when run by JDK-1.6, with the following output:
Press Enter to interrupt I/O
XXXX
Interrupting...
Closed via Thread.interrupt()
— meaning that only 128k of data was written to the TCP socket's buffer.
When run by JDK-1.7 (1.7.0_25-b15 and 1.7.0-u40-b37), however, the very same code bails out with an IOException:
Press Enter to interrupt I/O
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXX
Exception in thread "main" java.io.IOException: Broken pipe
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:487)
at com.example.TestBlockingNio.main(TestBlockingNio.java:109)
Can anyone explain this different behaviour?