Search code examples
javasocketsexceptionnio

Java NIO: connection forcibly closed


I was trying to implement a simple HTTP client using java NIO. But I get an error that the connection was forcibly closed by the remote host before the all data was read. Using ordinary sockets, everything works fine.

Here's an example:

private static final String REQUEST = "GET / HTTP/1.1\r\nHost: stackoverflow.com\r\n\r\n";

void channel() {
    try {
        SocketChannel sc = SocketChannel.open(new InetSocketAddress("stackoverflow.com", 80));
        while (!sc.isConnected()) {
        }

        ByteBuffer buf = ByteBuffer.allocate(16*1024);
        buf.put(REQUEST.getBytes());
        buf.rewind();
        sc.write(buf);

        buf.rewind();
        while (sc.read(buf) > 0) {
            buf.rewind();
            System.out.println(new String(buf.array()));
            buf.clear();
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}

void socket() {
    try {
        Socket s = new Socket("stackoverflow.com", 80);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));

        out.write(REQUEST);
        out.flush();

        String l;
        while ((l = in.readLine()) != null) {
            System.out.println(l);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    // Works:
    new Test().socket();
    // Exception:
    new Test().channel();
}

This is the exception I get:

java.io.IOException: An existing connection was forcibly closed by the remote host
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(Unknown Source)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
at sun.nio.ch.IOUtil.read(Unknown Source)
at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
at at.maph.tlsproxy.client.Test.channel(Test.java:39)
at at.maph.tlsproxy.client.Test.main(Test.java:70)

Has it something to do that I'm using a buffered reader with the socket, but not with the channel? If so, how can I make a channel buffer the read data?


Solution

  • Ok, I figured it out now after checking write()'s return value, which was 16.384, so random data was sent to the server. The problem was with calling rewind on the buffer, instead, flip has to be used:

    void channel() {
        try {
            SocketChannel sc = SocketChannel.open(new InetSocketAddress("stackoverflow.com", 80));
    
            ByteBuffer buf = ByteBuffer.allocate(16*1024);
            buf.put(REQUEST.getBytes());
            buf.flip();     // <--------- Here
            sc.write(buf);
    
            buf.rewind();
            while (sc.read(buf) > 0) {
                buf.flip();   // <------- And here
                System.out.println(new String(buf.array()));
                buf.clear();
            }
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    }