Search code examples
javaniobytebuffersocketchannel

Java NIO. Why flip() method breaks my program?


Java code below:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class Test {
    public static void main(String args[]) throws IOException {

        SocketChannel c = SocketChannel.open();
        c.connect(new InetSocketAddress("google.com", 80));

        ByteBuffer b = ByteBuffer.allocate(1024);
        b.put("Request".getBytes());

        System.out.println("Write: " + c.write(b));

        int i;
        while ((i = c.read(b)) != -1) {

            System.out.println("Read: " + i);
            b.clear();

        }
    }
}

Actual Result:

Write: 1017 Read: 0 Read: 1024 Read: 44

First time, method read() read 0 bytes. It is not cool.

I modified my code:

    b.put("Request".getBytes());

    System.out.println("Write: " + c.write(b));

    b.flip(); //I added this line
    int i;
    while ((i = c.read(b)) != -1) {

        System.out.println("Read: " + i);
        b.clear();

    }

Actual results:

Write: 1017 Read: 1024 Read: 44

It already looks better. Thanks flip() for this!

Next, I put to buffer String "Request", this String has length 7, but method write()returned 1017.

What information method wrote to channel?

I am not sure, that method wrote string "Request".

Ok, I modified my code again:

    b.put("Request".getBytes());

    b.flip(); // I added this line
    System.out.println("Write: " + c.write(b));

    b.flip();
    int i;
    while ((i = c.read(b)) != -1) {

        System.out.println("Read: " + i);
        b.clear();

    }

Actual results:

Write: 7

and code crashed...

By why? Where is my mistake?

Thanks.


Solution

  • The flip method needs to be called before reading data from the buffer. The flip() method, reset the buffer's limit to the current position and reset the buffer's position to 0.

    So, if you have 7 byte of data in ByteBuffer, your position (starting from 0), would be 7. flip()'ing it, would make limit = 7, position = 0. Now, reading can occur.

    Here's an example on how to best use flip():

    public static final void nioCopy(ReadableByteChannel input, WritableByteChannel output) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
        while (input.read(buffer) != -1) {
            //Flip buffer
            buffer.flip();
            //Write to destination
            output.write(buffer);
            //Compact
            buffer.compact();
        }
    
        //In case we have remainder
        buffer.flip();
        while (buffer.hasRemaining()) {
            //Write to output
            output.write(buffer);
        }
    }