This discussion is archived
3 Replies Latest reply: May 1, 2012 11:21 PM by EJP RSS

Setting OP_WRITE

sabre150 Expert
Currently Being Moderated
I am writing my first non-play NIO server and have been trying to set OP_WRITE on a SelectionKey object when I have data to write and remove OP_WRITE when my queue of data is empty. Most tutorials I can find seem to indicate that this is unnecessary and suggest that one should write the data directly to the SocketChannel but since my data can for a short time (several seconds) arrive faster than I can send it then this would block if/when the socket write buffer filled. To stop this blocking I queue the data and want to set OP_WRITE when there is data in the queue and reset OP_WRITE when the queue is empty.

I have two method to perform this action -
    private void resetOP_WRITE()
    {
        final int newOps = key_.interestOps() & ~SelectionKey.OP_WRITE;
        key_.interestOps(newOps);
    }

    private void setOP_WRITE()
    {
        final int newOps = key_.interestOps() | SelectionKey.OP_WRITE;
        key_.interestOps(newOps);
    }
which do seem to set the interestOP values correctly but these do not seem to trigger the Selector.select() call so that it remains blocked.

Two points -

1) Is my basic approach of only setting OP_WRITE when I have data to send correct?

2) What am I missing with regards to unblocking the Selector.select() when I modify the interestOP values.
  • 1. Re: Setting OP_WRITE
    EJP Guru
    Currently Being Moderated
    this would block if/when the socket write buffer filled
    No, it would return zero from the write.
    1) Is my basic approach of only setting OP_WRITE when I have data to send correct?
    That's one way. The other way is just do the write and only set OP_WRITE if & when you get the zero return.
    2) What am I missing with regards to unblocking the Selector.select() when I modify the interestOP values.
    If you're doing this in a separate thread from the selector thread, it will block on an internal synchronization, so you need to wakeup() the selector thread first and code its selector loop such that it won't get back around to the select() until your OP_WRITE set/reset is done: these methods need to synchronize on the selector. The selector won't react to the new values of interestOps() until the next select() invocation anyway.
  • 2. Re: Setting OP_WRITE
    sabre150 Expert
    Currently Being Moderated
    Thanks EJP. I missed altogether the fact that the write would return zero! Shows I still am not thinking in non-blocking terms.

    I am setting OP_WRITE outside of the selector thread and last night while reading your book again I came to understand that I needed to wakeup() the selector thread. I was wrongly assuming that key_.interestOps(newOps) would do the wakeup(). Looks like my present design needs tweaking to allow access to the selector. Maybe another 20 or so reads of 4.6.2 will help me.

    Edited by: sabre150 on May 2, 2012 7:00 AM
    :-) I have just re-read the Javadoc for Selector and it is all in there! No design change is needed since the key has a reference to the Selector!

    Edited by: sabre150 on May 2, 2012 7:10 AM
    So with the addition of two identical lines of code my server now basically works (well it does not actually fall over and the tunnel transfers stuff). I now have to worry about how to close it properly!
  • 3. Re: Setting OP_WRITE
    EJP Guru
    Currently Being Moderated
    Well done. You will see well-meaning blogs to the effect that you need a queue of pending interestOps changes to be processed by the selector thread, but wakeup() and proper synchronization on the Selector seem all that's required to me.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points