I just wrote some code to try and implement a simple packet protocol using NIO.SocketChannel. I'm having trouble with reading data from the channels though. What I'm doing is reading in a certain number of bytes which form the header of my protocol during one selectNow() operation. I do this so I can create a new ByteBuffer with the exact size of the packet. That part works great. But then I never get another SelectionKey.isReadable() event from any future selectNow() operations. It's like NIO just discards the rest of the data. Does anyone know why this would happen, or if there is a way to get the Selector to fire off another SelectionKey.isReadable() event?
Here's my code (trimmed down to the vital stuff):
Snippet from SMLIOManager (the class that contains the Selector and lets the SMLIOSocketPacket classes know when their SelectionKeys are ready):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void fire() { selector.selectedKeys().clear(); try { selector.selectNow(); } catch (Exception e) { LogManager.getLogManager().getLogger("sml.io").info("Exception in SMLIOManager.fire: " + e); } Iterator i = selector.selectedKeys().iterator(); if (selector.selectedKeys().size() > 0) LogManager.getLogManager().getLogger("sml.io").finer("SMLIOManager.fire.selector.selectNow returned " + selector.selectedKeys().size() + " of " + selector.keys().size() + " keys."); while (i.hasNext()) { SelectionKey key = (SelectionKey)i.next(); ((SMLIO)key.attachment()).stateReady(); } }
|
Snippet from SMLIOSocketPacket (the class that implements the protocol) (and extends SMLIO)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| void stateReady() { LogManager.getLogManager().getLogger("sml.io").info(name + " entered stateReady"); SocketChannel chan = (SocketChannel)key.channel(); if (key.isWritable()) { LogManager.getLogManager().getLogger("sml.io").info(name + ".key.isWritable"); try { ByteBuffer out = (ByteBuffer)outQueue.getFirst(); if (out.position() == out.limit()) { outQueue.removeFirst(); if (outQueue.size() > 0) { out = (ByteBuffer)outQueue.getFirst(); } else { key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); out = null; } } if (out != null) { chan.write(out); } } catch (Exception e) { LogManager.getLogManager().getLogger("sml.io").info(name + ".stateReady: " + e); } } if (key.isReadable()) { LogManager.getLogManager().getLogger("sml.io").info(name + ".key.isReadable"); try { if (inBuff.position() == inBuff.limit()) { if (isHeader == true) { inBuff.flip(); int len = inBuff.getInt(); inBuff = ByteBuffer.allocate(len); isHeader = false; } else { listener.recieveInput(inBuff, this); inBuff = ByteBuffer.allocate(HEADER_LEN); isHeader = true; } } int val = chan.read(inBuff); LogManager.getLogManager().getLogger("sml.io").info(name + " read " + val + " bytes of data."); } catch (Exception e) { LogManager.getLogManager().getLogger("sml.io").info("Exception in " + name + ".stateReady: " + e); } } } |
Looking at my log file, I noticed that only 1 "name read XXX bytes of data." is recorded, and it was the size of the header. Also, there was only 1 "name.key.isReadable" in the log file as well.
Any suggestions?

[size=10pt][/size]