IOException during blocking network NIO in JDK 1.7

Posted by Bass on Stack Overflow See other posts from Stack Overflow or by Bass
Published on 2013-10-21T15:51:56Z Indexed on 2013/10/21 15:53 UTC
Read the original article Hit count: 216

Filed under:
|
|

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?

© Stack Overflow or respective owner

Related posts about java

Related posts about java-7