Search code examples
javaniobytebuffersocketchannel

SocketChannelImpl.write(ByteBuffer[] srcs, int offset, int length) appends ByteBuffer of size 0


I have a client-server application communicating over Java NIO sockets which makes use of the SocketChannelImpl class underneath. When from the senders side, I send a ByteBuffer array of length n elements, the client always receives ByteBuffer array of length n+1 elements with the last ByteBuffer always being of the size 0.

I was wondering if that is some sort of an EOF indicator automatically sent by the SocketChannelImpl class to indicate a completed send of an array of ByteBuffers so that when the receiving side receives an array ByteBuffers followed by a BytBuffer of size 0 it knows that it has correctly received the ByteBuffer array that was sent from the senders side?

Update: Adding example to further elaborate on my question:

Whenever a call to SocketChannel.write(ByteBuffer[] srcs, int offset, int length) is made on the senders side and SocketChannel.read(ByteBuffer srcs) is made on the receivers side, I log the length of the array and the size of its element. Following is a set of logs from senders and receiver side:

Sender:

Writing using:write(ByteBuffer[] srcs, int offset, int length)
srcs.length == 2, totalBytesWritten = 1326

Receiver:

Read using read(ByteBuffer src)
totalBytesRead:4
totalBytesRead:1322
totalBytesRead:0

What I am asking is, why on the receiver side even though the amount of data that was sent by the sender(1326 bytes) is received by the client(4+1322), there is an extra call to the read(ByteBuffer src) is made which ends of reading 0 bytes. My (ill informed) guess was that was some kind of an EOF indicator, but from the comments on the question it looks like that has to do something with how the application itself goes about reading data from the channels.


Solution

  • SocketChannelImpl.write(ByteBuffer[] srcs, int offset, int length) appends ByteBuffer of size 0

    No it doesn't.

    I have a client-server application communicating over Java NIO sockets which makes use of the SocketChannelImpl class underneath.

    Forget about what's underneath. You are using java.nio.channels.SocketChannel.

    When from the senders side, I send a ByteBuffer array of length n elements

    You don't. You send the contents. The sending ByteBuffer[] array is gathered into a byte stream and sent as bytes.

    the client always receives ByteBuffer array of length n+1 elements with the last ByteBuffer always being of the size 0.

    No it doesn't. The received bytes are scattered into another ByteBuffer[] array, if that's what you use to read the channel. If you use gather-write and scatter-read there is no relationship between the sending and receiving ByteBuffer arrays other than the actual bytes received.

    I was wondering if that is some sort of an EOF indicator automatically sent by the SocketChannelImpl class to indicate a completed send of an array of ByteBuffers

    No.

    so that when the receiving side receives an array ByteBuffers

    It doesn't. It receives a byte stream, into an array of ByteBuffers that it provided itself.

    followed by a ByteBuffer of size 0 it knows that it has correctly received the ByteBuffer array that was sent from the senders side?

    This doesn't begin to make sense. ByteBuffers are neither send nor received, either individually or as arrays.

    Update: Adding example to further elaborate on my question:

    There is no example here, only some output. An example would be useful but it would have to consist of Java code.

    Whenever a call to SocketChannel.write(ByteBuffer[] srcs, int offset, int length) is made on the senders side and SocketChannel.read(ByteBuffer srcs)

    Can we assume this should be SocketChannel.read(ByteBuffer[] srcs)? It doesn't make sense otherwise.

    is made on the receivers side, I log the length of the array and the size of its element. Following is a set of logs from senders and receiver side:

    Sender:

    Writing using:write(ByteBuffer[] srcs, int offset, int length)
    srcs.length == 2, totalBytesWritten = 1326
    

    Receiver:

    Read using read(ByteBuffer src)
    totalBytesRead:4
    totalBytesRead:1322
    totalBytesRead:0
    

    This can only mean two things:

    1. You used read(ByteBuffer src) and called it three times; the peer had only sent 1326 bytes; so the third read returned zero, meaning no data was available to be read.

    OR

    1. You used read(ByteBuffer[] srcs), where srcs contained three ByteBuffers: one of length exactly 4, one of length >= 1322, and one of length > 0; only 1326 bytes were received, so the third ByteBuffer was cleared, or unaffected.

    What I am asking is, why on the receiver side even though the amount of data that was sent by the sender(1326 bytes) is received by the client(4+1322), there is an extra call to the read(ByteBuffer src) is made which ends of reading 0 bytes.

    There is no such call, unless you made it, and if you made it when there was no data available to be read you got zero bytes. Why is this surprising?

    My (ill informed) guess was that was some kind of an EOF indicator

    No. End of stream is signalled by read() returning -1.

    but from the comments on the question it looks like that has to do something with how the application itself goes about reading data from the channels.

    Correct. You tried to read beyond the end of the data that was sent, or with more ByteBuffers than were required to hold the data that was received. Simple as that.