Writting data to a SocketChannel using NIO

F

Fritz Bayer

Hello,

I'm having problems with writting data to a SocketChannel. The problem
is that my program gets caught in an infinite loop, after running for
hours without a problem.

I have a ByteBuffer containing data, which I want to write to a
SocketChannel. I do this the whole time again and agian, until the
ByteBuffer is empty and then I continue.

This happens over and over again.

The problem is though that once in a while (usually after a couple of
hours) no data can be written to the SocketChannel and therefore I end
up in an infinite loop.

On the other hand I can't just continue, when no bytes have been
written, since that actually happens almost all of the time, when
writting data to the channel. It almost always takes a couple of
writes to empty the whole ByteBuffer. And inbetween those writes you
get zero writes, which means no bytes had been written, as well.

Here is the important code snippet:

int bytesRead = 0;

byteBuffer.clear();

int loops = 0;

while ((bytesRead = inputChannel.read(byteBuffer)) > 0)
{
timestampOfLastRead = System.currentTimeMillis();

byteBuffer.flip();

long lastTimeWeReadBytes = System.currentTimeMillis();

while (byteBuffer.hasRemaining())
{
int bytesWritten = outputChannel.write(byteBuffer);

if (bytesWritten != 0)
lastTimeWeReadBytes = System.currentTimeMillis();
else
assert System.currentTimeMillis() - lastTimeWeReadBytes < 60000 :
" We are trying since " + (System.currentTimeMillis() -
lastTimeWeReadBytes) + " ms to write data to a socket channel and have
failed. This is bad. How do we avoid this. We can't just stop if
byteesWritten=0 since thats very often the case";
}

assert byteBuffer.limit() > 0 && byteBuffer.capacity() > 0 && !
byteBuffer.hasRemaining() : "Of course this has to be true after we
are done. If not somthing is really messed up";
}

This writting stuff is confusing. I know that usually you get informed
when data can be written to a socketchannel.

However, this funtion get basically called on every key on every
selection, since most of the time data can be written.

And actually I read on the sun site that you just write the data when
you have it to the socketchannel.

However, I know from pratice that:

1. To empty a ByteBuffer and to write all its data you have to call
write several times. Sometimes you write small chunks. Sometimes you
write nothing. And sometimes you write all the data at once.

2. If you follow the policy that you stop writting, when no data was
written you are left with data which still has to be send.

If you don't get another isReadable() call on the input SocketChannel,
then you won't be able to send the data at all and the other side
never gets it, which is bad too.

3. If you write until the ByteBuffer has been emptied, then this works
for hours. But it fails after a while. What happens is that you will
write no bytes at all forever.

I thought about to check the SelectorKey.isWriteable before writting
the data and stop writting data if the call return false.

However, then I'm stuck with unsent data. Of course that's better then
being stuck in an infinte loop.

However, I would be very happy about some feedback from the
experienced and practice proven nio programmers. If you know about
this problem I would be very happy to hear what you suggest!

Fritz
 
E

Esmond Pitt

The best way is to assume that you can write until you get a return
value of zero from the write call. When this happens on a channel you
should register the channel for OP_WRITE. Whenever you succeed in
writing all the data you asked to write, you should deregister for OP_WRITE.

EJP
 
F

Fritz Bayer

Esmond Pitt said:
The best way is to assume that you can write until you get a return
value of zero from the write call. When this happens on a channel you
should register the channel for OP_WRITE. Whenever you succeed in
writing all the data you asked to write, you should deregister for OP_WRITE.

EJP

That's excatly what I figured. What do you think about testing
isWriteable() in the SelectionKey at that point?

Of course the state is lilkely to be obsolete unless the channels was
not writeable at the time, when last selection via select() took
place.
 
E

Esmond Pitt

Fritz said:
What do you think about testing
isWriteable() in the SelectionKey at that point?
Absolutely.

Of course the state is lilkely to be obsolete unless the channels was
not writeable at the time, when last selection via select() took
place.

The state held in a SelectionKey resulting from a select() is in
principle *always* obsolete. This doesn't matter in practice unless you
have other threads playing with the same socket channels, as incoming
data or connections or outgoing buffer space won't just go away. In
other words isAcceptable(), isReadable(), isConnectable(), is Writable()
are always obsolete but always reliable.

(However of course their *negations* are obsolete but *not* reliable, as
e.g. !isWritable() can change very quickly, you only have to drain one
byte to the network.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top