Java NIO channel never becomes readable

Discussion in 'Java' started by nooneinparticular314159@yahoo.com, Mar 17, 2008.

  1. Guest

    I have a Java NIO channel that is never readable. It does become
    writable. I initially register it inside of an event loop as shown
    below (I've only included the relevant snippets of code):

    SelectionKey NextKey = (SelectionKey) KeyIterator.next();
    if (NextKey.isAcceptable()) {
    SocketChannel AcceptedChannel = null;
    ServerSocketChannel ServerChannel = (ServerSocketChannel)
    NextKey.channel();
    AcceptedChannel = ServerChannel.accept();
    AcceptedChannel.configureBlocking(false);
    AcceptedChannel.register(ChannelSelector, SelectionKey.OP_READ |
    SelectionKey.OP_WRITE);

    and then I test to see if I can read and write:

    if (NextKey.isReadable()) {
    do fun reading stuff, like reading data from the channel
    }

    if (NextKey.isWritable()) {
    do exciting writing stuff, like writing data to the channel!
    }

    While I do seem to be able to *write* to the channel, I am completely
    unable to read, as the NextKey never becomes readable. I've tried
    changing the registration of the channel at various points to read
    only or write only, but that doesn't help. What I'm trying to do is
    get two clients to talk to each other using NIO. What I have wound up
    with is each client yelling at the other, but neither of them
    listening to what the other says! What am I doing wrong here? Why
    does NextKey never become readable? How can I fix it? I've checked
    every Java NIO reference I can find, and nothing helps...

    Thanks!
     
    , Mar 17, 2008
    #1
    1. Advertising

  2. Mark Space Guest

    wrote:

    > only or write only, but that doesn't help. What I'm trying to do is
    > get two clients to talk to each other using NIO. What I have wound up
    > with is each client yelling at the other, but neither of them
    > listening to what the other says! What am I doing wrong here? Why
    > does NextKey never become readable? How can I fix it? I've checked
    > every Java NIO reference I can find, and nothing helps...


    Are you sure you write to the channel? Do you ever flush your writes?

    Can you, for example, run telnet listening on the port you are using and
    verify it receives what you write?

    Can you read from this channel with out using NIO? It might be best to
    start with something (test harness first!) easier to debug, then get NIO
    working.
     
    Mark Space, Mar 17, 2008
    #2
    1. Advertising

  3. Guest

    On Mar 16, 11:10 pm, Mark Space <> wrote:
    > wrote:
    > > only or write only, but that doesn't help.  What I'm trying to do is
    > > get two clients to talk to each other using NIO.  What I have wound up
    > > with is each client yelling at the other, but neither of them
    > > listening to what the other says!  What am I doing wrong here?  Why
    > > does NextKey never become readable?  How can I fix it?  I've checked
    > > every Java NIO reference I can find, and nothing helps...

    >
    > Are you sure you write to the channel? Do you ever flush your writes?
    >
    > Can you, for example, run telnet listening on the port you are using and
    > verify it receives what you write?
    >
    > Can you read from this channel with out using NIO?  It might be best to
    > start with something (test harness first!) easier to debug, then get NIO
    > working.


    That's a brilliant idea (telnet)! I'd never thought of trying that.
    So I just did, and yes, the data is being written. I can also verify
    that it DOES read data by typing a response in telnet. So what seems
    to happen is that my program receives the data, but the channel never
    gets set to read. So what could be causing this problem, and how do I
    get it to read?

    Thanks!
     
    , Mar 17, 2008
    #3
  4. Guest

    On Mar 16, 11:10 pm, Mark Space <> wrote:
    > wrote:
    > > only or write only, but that doesn't help.  What I'm trying to do is
    > > get two clients to talk to each other using NIO.  What I have wound up
    > > with is each client yelling at the other, but neither of them
    > > listening to what the other says!  What am I doing wrong here?  Why
    > > does NextKey never become readable?  How can I fix it?  I've checked
    > > every Java NIO reference I can find, and nothing helps...

    >
    > Are you sure you write to the channel? Do you ever flush your writes?
    >
    > Can you, for example, run telnet listening on the port you are using and
    > verify it receives what you write?
    >
    > Can you read from this channel with out using NIO?  It might be best to
    > start with something (test harness first!) easier to debug, then get NIO
    > working.


    Transmitting through Telnet, I get the following error, which I
    suspect is the result of my sending bogus data through telnet, rather
    than following the proper protocol:

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at
    BitTorrent.NetworkDataHandler.ReadMessageFromChannel(NetworkDataHandler.java:
    412)
    at BitTorrent.Main.main(Main.java:343)
    Java Result: 1

    I don't *think* that this is the cause of my not getting readable
    channels though, since I've verified that the channel key is never
    readable.

    The channel does become readable when I transmit through telnet
    though, and the client is clearly transmitting data when I connect
    with telnet. What is happening here?

    Thanks!
     
    , Mar 17, 2008
    #4
  5. EJP Guest

    wrote:
    > The channel does become readable when I transmit through telnet
    > though, and the client is clearly transmitting data when I connect
    > with telnet. What is happening here?

    That indicates that your sending code is incorrect. If it's NIO code, it
    needs to flip() the buffer before the write, compact() it afterwards,
    and examine the count returned by the write() call. If that was zero,
    you need to register the channel for OP_WRITE, and when it happens,
    retry all that. If you *didn't* get zero, deregister OP_WRITE.
     
    EJP, Mar 17, 2008
    #5
  6. Guest

    Ok. I think I'm closer, but I'm still doing something slightly
    wrong. My writing code looks like:

    SetChannelForWritingOnly(); //This method does a
    Channel.register(ChannelSelector,
    //SelectionKey.OP_WRITE);


    SendBuffer.flip();
    BytesWrittenToChannel = Channel.write(SendBuffer);
    SendBuffer.compact();
    SetChannelForReadingOnly();

    When I write to the channel, BytesWrittenToChannel is 0. So no bytes
    are actually written. So I am registering the channel for writing
    before, flipping the buffer before the write, compacting it
    afterwards, and still getting 0. Huh?

    Thanks!
     
    , Mar 17, 2008
    #6
  7. Guest

    I should probably note that I have two buffers here: a send buffer and
    a receive buffer. I always write to the sendbuffer, and I always read
    from the receive buffer. I tried getting rid of the flip, and I was
    suddenly able to write to the channel (although the other side still
    doesn't read it!) The same data seems to get written to the channel
    over and over again (possibly until the buffer on the other side fills
    up?), after which, I get no ready channels...
     
    , Mar 17, 2008
    #7
  8. Guest

    A further followup - when the data is written to the channel, the
    position in the buffer does not appear to change. For example, when I
    do:

    BytesWrittenToChannel = Channel.write(SendBuffer);

    The contents of SendBuffer before and after the write are identical.
    The limit, capacity, and position do not change. If I do a
    SendBuffer.flip or SendBuffer.clear(), it still doesn't change
    anything in the SendBuffer! So the sendbuffer always contains the
    data that I originally put into it, it keeps writing out, and it never
    gets cleared. That data is received over my telnet connection if I
    telnet to the program, but is never read in by my actual client, as
    noted previously. Any idea why this might be happening? It's my
    understanding that performing a write is supposed to consume the
    contents of the buffer (or at least as much as is written), but this
    doesn't seem to be happening.

    Thanks!
     
    , Mar 17, 2008
    #8
  9. Guest

    Another followup - I've recorded the transmissions using Ethereal (aka
    Wireshark). Both clients are clearly transmitting to each other.
    (After removing the Channel.flip and clear statements, the clients
    transmit properly.) Ethereal shows that the transmissions sent are
    exactly what should be sent. The problem is that the clients never
    have OP_READ flag set for the channel. So this brings me back to my
    original question - why doesn't OP_READ ever get set, and how can I
    correct this?

    Thanks!
     
    , Mar 17, 2008
    #9
  10. EJP Guest

    wrote:
    > The contents of SendBuffer before and after the write are identical.
    > The limit, capacity, and position do not change. If I do a
    > SendBuffer.flip or SendBuffer.clear(), it still doesn't change
    > anything in the SendBuffer!


    All that indicates that there is nothing to write, i.e. position = limit.

    NB I think the result of a ByteBuffer.wrap() is already flipped for some
    reason.

    Re OP_READ, are you registering the channel for OP_READ?
     
    EJP, Mar 18, 2008
    #10
  11. Guest

    > All that indicates that there is nothing to write, i.e. position = limit.
    >
    > NB I think the result of a ByteBuffer.wrap() is already flipped for some
    > reason.
    >
    > Re OP_READ, are you registering the channel for OP_READ?


    I'm initially registering the channel as:
    AcceptedChannel.register(ChannelSelector, SelectionKey.OP_READ |
    SelectionKey.OP_WRITE);
    (I've also tried setting it up intially as:
    AcceptedChannel.register(ChannelSelector, SelectionKey.OP_READ);
    but that doesn't seem to work (as it shouldn't, since I need to be
    able to both read and write.)

    The next thing it hits (assuming that there is a key) is usually if
    (NextKey.isWritable())
    (It hits the test for readability first, but I never get a readable
    channel)

    It gets the appropriate channel based on that key:
    NetworkDataHandler Handler = DataHandlerContainer.Get((SocketChannel)
    NextKey.channel());

    and then the object associated with that specific channel tries to set
    up a message and write to it:
    MessageHandlerForThisChannel.SendTestMessage();

    That creates a test message (currently a string about wishing that my
    program would work!), encodes it in a byte array, and adds it to my
    outgoing message queue.

    A message sending method is then called, which checks for messages on
    the queue. If any exist, it gets the next one and places it in the
    SendBuffer. It then does a

    Channel.write(SendBuffer);

    to write out the data. I've tried various combinations of registering
    teh channel for OP_READ, OP_READ | OP_WRITE, or OP_WRITE after this,
    and none of them worked (although registering for read only certainly
    prevented more data from being written. :) )

    After the data is written out to the channel, it definitely appears on
    the remote host. Using Ethereal, I've been able to confirm that both
    clients send the test message to each other. Using Telnet, I've also
    been able to confirm that the message is sent to remote clients.
    Ethereal also confirmed that both clients are writing to and from the
    same ports on each machine, so they are clearly using the same channel
    in each direction. However, despite the data making it at least as
    far as the remote host, the OP_READ is never triggered, and therefore
    the data is never read. Unless, of course, I send the data through
    telnet, in which case it is. Actually, I also tried writing a non-
    blocking client that does an OP_CONNECT instead of a read or write,
    that one seems to be able to get data through to the client (although
    it doesn't try to read any.) That client uses the same reading and
    writing methods as my regular client. Only the setup is different.

    Any ideas? What else can I try?

    Thanks!
     
    , Mar 18, 2008
    #11
  12. EJP Guest

    wrote:
    > (I've also tried setting it up intially as:
    > AcceptedChannel.register(ChannelSelector, SelectionKey.OP_READ);
    > but that doesn't seem to work (as it shouldn't, since I need to be
    > able to both read and write.)


    Nothing to do with it. You can write any time. You should only register
    OP_WRITE when you got a zero return from channel.write(); then when
    OP_WRITE fires, repeat the write, and if it succeeded completely (i.e.
    !buffer.hasRemaining()), deregister OP_WRITE.

    > The next thing it hits (assuming that there is a key) is usually if
    > (NextKey.isWritable())


    Of course. The channel is almost always writable, unless you've filled
    the send buffer. That's why you should only register OP_WRITE when you
    know that has occurred.

    > (It hits the test for readability first, but I never get a readable
    > channel)


    So there is nothing to read.

    > However, despite the data making it at least as
    > far as the remote host, the OP_READ is never triggered, and therefore
    > the data is never read.


    If the remote host is written the same way as this, it is probably too
    busy spinning on OP_WRITE. In any case until the remote host has read
    the request it won't write a response, will it? which would explain why
    you never get a readable channel in the client.

    > Unless, of course, I send the data through telnet,


    Can't account for that, but there are enough mistakes already that you
    need to fix and re-test.

    in which case it is. Actually, I also tried writing a non-
    > blocking client that does an OP_CONNECT instead of a read or write,
    > that one seems to be able to get data through to the client (although
    > it doesn't try to read any.) That client uses the same reading and
    > writing methods as my regular client. Only the setup is different.


    If you use OP_CONNECT you must deregister it when it fires, as under the
    hood it's the same as OP_WRITE.
     
    EJP, Mar 18, 2008
    #12
  13. Guest

    On Mar 18, 4:26 pm, EJP <> wrote:
    > wrote:
    > > (I've also tried setting it up intially as:
    > > AcceptedChannel.register(ChannelSelector, SelectionKey.OP_READ);
    > > but that doesn't seem to work (as it shouldn't, since I need to be
    > > able to both read and write.)

    >
    > Nothing to do with it. You can write any time. You should only register
    > OP_WRITE when you got a zero return from channel.write(); then when
    > OP_WRITE fires, repeat the write, and if it succeeded completely (i.e.
    > !buffer.hasRemaining()), deregister OP_WRITE.
    >
    > > The next thing it hits (assuming that there is a key) is usually if
    > > (NextKey.isWritable())

    >
    > Of course. The channel is almost always writable, unless you've filled
    > the send buffer. That's why you should only register OP_WRITE when you
    > know that has occurred.
    >
    > > (It hits the test for readability first, but I never get a readable
    > > channel)

    >
    > So there is nothing to read.
    >
    > > However, despite the data making it at least as
    > > far as the remote host, the OP_READ is never triggered, and therefore
    > > the data is never read.

    >
    > If the remote host is written the same way as this, it is probably too
    > busy spinning on OP_WRITE. In any case until the remote host has read
    > the request it won't write a response, will it? which would explain why
    > you never get a readable channel in the client.
    >
    > > Unless, of course, I send the data through telnet,

    >
    > Can't account for that, but there are enough mistakes already that you
    > need to fix and re-test.
    >
    >   in which case it is.  Actually, I also tried writing a non-
    >
    > > blocking client that does an OP_CONNECT instead of a read or write,
    > > that one seems to be able to get data through to the client (although
    > > it doesn't try to read any.)  That client uses the same reading and
    > > writing methods as my regular client.  Only the setup is different.

    >
    > If you use OP_CONNECT you must deregister it when it fires, as under the
    > hood it's the same as OP_WRITE.


    I'm confused. If you never register OP_WRITE unless the client can't
    write to the channel, then how does the code to write in the first
    place ever get called? ie. You test to see if the channel is
    writable. If it is, you write something. If it isn't, that section
    of code will never get called, and you will never get the chance to
    write.

    >> (It hits the test for readability first, but I never get a readable
    >> channel)


    >So there is nothing to read.


    But I'm sure that there is something to read. In fact, I can have one
    client write repeatedly until the receive buffer gets filled. Then it
    stops writing because it can no longer do so. But even when this
    happens, OP_READ is never triggered. Huh?

    >If the remote host is written the same way as this, it is probably too
    >busy spinning on OP_WRITE. In any case until the remote host has read
    >the request it won't write a response, will it? which would explain why
    >you never get a readable channel in the client.


    In this case, both clients are identical. The way it works is one
    client connects to the other. when it does so, it sends some initial
    data. Both clients send this data first thing, before anything else
    happens. So they should both have data to read. But somehow, they
    don't.

    The OP_CONNECT isn't actually part of my client code - it was just
    there from a testing program. But it does trigger a read on the
    client...

    I'll try setting everything to OP_READ except in the situation you
    mentioned and report back what happens. I'm pretty sure that I've
    tried this before though, and when I do, the clients just sit there
    and don't write (and therefore have nothing to read). I'll also try
    removing the test for writing, as I think you've suggested, and maybe
    that will help. More shortly...

    Thanks!
     
    , Mar 19, 2008
    #13
  14. Mark Space Guest

    wrote:

    > I'm confused. If you never register OP_WRITE unless the client can't
    > write to the channel, then how does the code to write in the first


    I'm guessing here, but EJP did say to try to write first. Then, if the
    bytes written was 0, only then register OP_WRITE.

    It makes sense to me. Only register OP_WRITE if the out-bound channel
    is stuffed full and won't take any more, that's when you need to be
    notified when it's ready again. Otherwise, just stuff more in there.
     
    Mark Space, Mar 19, 2008
    #14
  15. Guest

    Results:
    Always setting to OP_READ: one client manages to write something to
    the channel, but the other never gets a readable key, and therefore
    never looks in the buffer.

    Always setting to OP_READ + removing the test for NextKey.isWritable:
    I get a class casting exception when I try to do:

    DataHandlerContainer.Get((SocketChannel) NextKey.channel());

    (This has never happened before. The DataHandlerContainer contains
    the objects that I use to write to channels. I have one such object
    per channel. I have many clients that I might need to communicate
    with, which is why I am dependent on the key to tell me which channel
    to write to, and therefore which object to have writing to that
    channel.)

    Always setting to OP_READ, but setting the channel to OP_READ |
    OP_WRITE just before I write has no effect. One client still writes.
    The other never does. Neither reads. However, occasionally a crash
    occurs, and the buffer on the other client suddenly becomes readable
    (once with actual data in the buffer!)
     
    , Mar 19, 2008
    #15
  16. EJP Guest

    wrote:
    > Always setting to OP_READ: one client manages to write something to
    > the channel, but the other never gets a readable key, and therefore
    > never looks in the buffer.


    Did the write return a non-zero result? If not, you haven't written
    anything yet.

    > Always setting to OP_READ + removing the test for NextKey.isWritable:
    > I get a class casting exception when I try to do:
    >
    > DataHandlerContainer.Get((SocketChannel) NextKey.channel());


    That's a bug in your code.

    > Always setting to OP_READ, but setting the channel to OP_READ |
    > OP_WRITE just before I write has no effect.


    It's not *supposed* to have any effect. These OP_* things just tell the
    selector what you want it to wake up on. They're not there to determine
    what I/O APIs you're allowed to call.

    You'll have to show us some code for this to get any further. You seem
    to have a lot of misconceptions about how all this is supposed to work.
     
    EJP, Mar 19, 2008
    #16
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. farseer
    Replies:
    2
    Views:
    469
    farseer
    Apr 11, 2005
  2. Replies:
    9
    Views:
    984
    Juha Nieminen
    Aug 22, 2007
  3. Replies:
    6
    Views:
    674
    Gordon Beaton
    Mar 17, 2008
  4. Stef Mientki

    and becomes or and or becomes and

    Stef Mientki, May 22, 2011, in forum: Python
    Replies:
    9
    Views:
    318
    Chris Angelico
    May 28, 2011
  5. Jan Burse
    Replies:
    10
    Views:
    403
    Arne Vajhøj
    Nov 6, 2011
Loading...

Share This Page