Search code examples
javanonblockingsocketchanneljava-nio

What is the minimum number of written bytes of a SocketChannel when its key is writable?


Let's say we're going to write some bytes to a SocketChannel within a writable SelectionKey.


// in a single selection loop

if (selectedKey.isWritable()) {

    final var channel = (SocketChannel) selectedKey.channel();
    assert !channel.isBlocking(); // checked!

    final var buffer = (ByteBuffer) selectedKey.attachment();
    assert buffer.hasRemaining(); // checked!

    final var w = channel.write(buffer);
    assert w >= 0; // ok, no harm
    assert w >  0; // really?
}

My question is,

  • when a SelectionKey is writable
  • and the buffer has remaining,

Can I technically be assured that the result of the channel.write(buffer) is always positive?

In a same point of view, is the underlying socket's output buffer always has a free space when the selectedKey.isWritable() results true?

P.S. I already check the documentation.

Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all. A socket channel in non-blocking mode, for example, cannot write any more bytes than are free in the socket's output buffer.


Solution

  • Can I technically be assured that the result of the channel.write(buffer) is always positive?

    TL;DR: as the question is posed, no, there is no such assurance.

    The general model of operation for non-blocking channel I/O is that when an I/O operation is requested, as many bytes are transferred as can be done without blocking, up to a maximum of the number requested. That may be 0 bytes. Under the conditions you describe, that would normally be a positive number of bytes, but

    • If there is another thread that could attempt to write to the channel then between when the channel is selected for writability and when the thread you are focusing on attempts to write, the other thread could transfer enough bytes to the channel that it is no longer writable without blocking. In that case, the write() you are focusing on could return 0.

    • There are various conditions in which the write() could throw an exception instead of returning anything at all.

    • Even if neither of the above applies, Java simply does not provide a guarantee that you will see a positive number of bytes written in such a case, only that the attempt will not block. The write is highly likely to return a positive result if neither of the above points applies, and there may be platforms where you can safely rely on that, but Java does not assure it. Robust code should be prepared for the possibility that the write() returns 0.


    In a same point of view, is the underlying socket's output buffer always has a free space when the selectedKey.isWritable() results true?

    A channel's selection key indicating that the channel is writable means that at least one byte can be transferred to it without blocking. There is only indirect attestation to there being an underlying output buffer at all, though in practice, that is indeed how all socket implementations I know work. Supposing that there is indeed an output buffer, yes, the channel being writable means there is at least one byte of space available in that buffer.