Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (499)
Games in Android Showcase (118)
games submitted by our members
Games in WIP (567)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  What happens when not all data is read from a NIO.SocketChannel?  (Read 1252 times)
0 Members and 1 Guest are viewing this topic.
Offline crazyc94

Senior Newbie




I like cheese


« Posted 2005-11-26 04:34:53 »

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  
/*
 * This is where the selector is checked for readiness
 */

void fire()
{
   //The timer has fired, so check for I/O readiness
  selector.selectedKeys().clear(); //Make sure the set is cleared
  try
   {
      selector.selectNow(); //Fill the set with ready keys
  }
   catch (Exception e) //Some not so nice happened, so log it
  {
      LogManager.getLogManager().getLogger("sml.io").info("Exception in SMLIOManager.fire: " + e);
   }
   Iterator i = selector.selectedKeys().iterator(); //Get an iterator
 
   if (selector.selectedKeys().size() > 0) //Log how many keys are ready (if there are any ready)
     LogManager.getLogManager().getLogger("sml.io").finer("SMLIOManager.fire.selector.selectNow returned " +
         selector.selectedKeys().size() + " of "
         selector.keys().size() + " keys.");
   
   while (i.hasNext()) //Go through all the keys in the set
  {
      SelectionKey key = (SelectionKey)i.next(); //Get the next SelectionKey
     
      ((SMLIO)key.attachment()).stateReady(); //Tell the protocol manager that there is some I/O readiness, and to process it
  }
}


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"); //Log entrance into the method
 
   SocketChannel chan = (SocketChannel)key.channel(); //Get the channel
 
   if (key.isWritable()) //Is writable, so write as much as possible
  {
      LogManager.getLogManager().getLogger("sml.io").info(name + ".key.isWritable"); //Log is writable
     try
      {
         ByteBuffer out = (ByteBuffer)outQueue.getFirst(); //Get the first buffer in the queue of outgoing buffers
       
         if (out.position() == out.limit()) //Reached the end of the buffer
        {
            outQueue.removeFirst(); //Remove the buffer
           
            if (outQueue.size() > 0) //More buffers left in the queue, so use the next one
           {
               out = (ByteBuffer)outQueue.getFirst();
            }
            else //No more left
           {
               key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); //Say we don't want to write anymore
              out = null; //Prevent errors
           }
         }
         
         if (out != null) //If the buffer exists
        {
            chan.write(out); //Write the buffer
        }
      }
      catch (Exception e) //Something happened :(
     {
         LogManager.getLogManager().getLogger("sml.io").info(name + ".stateReady: " + e);
      }
   }
   
   if (key.isReadable()) //Is readable, so read in as much as possible
  {
      LogManager.getLogManager().getLogger("sml.io").info(name + ".key.isReadable"); //Log readability
     try
      {
         if (inBuff.position() == inBuff.limit()) //The buffer has been filled, so act appropriately
        {
            if (isHeader == true) //A header, so process it
           {
               inBuff.flip(); //Flip it to read the header
             
               int len = inBuff.getInt(); //Get the length of the packet
             
               inBuff = ByteBuffer.allocate(len); //Make a buffer to hold the packet
             
               isHeader = false; //Not a header any more
           }
            else //The data itself
           {
               listener.recieveInput(inBuff, this); //Dispatch this packet (this is implemented in an outside class, but is yet to be called in pratice :( )
             
               inBuff = ByteBuffer.allocate(HEADER_LEN); //Make a buffer to hold the header
             
               isHeader = true; //Now a header
           }
         }
         
         int val = chan.read(inBuff); //Read as much as we can (non-blocking)
       
         LogManager.getLogManager().getLogger("sml.io").info(name + " read " + val + " bytes of data."); //Log how much has been written
     }
      catch (Exception e) //Something happened :(
     {
         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?Huh[size=10pt][/size]

Quack!  I'm a duck!

"Or make your own RationalNumber class (unless you need irrational numbers, then you're screwed )." - shmoove
Offline crazyc94

Senior Newbie




I like cheese


« Reply #1 - Posted 2005-11-26 22:54:04 »

Nevermind, I figured out what was happening wrong.  In the method where I add a ByteBuffer to the outgoing queue, I flipped the buffer to record the length in the first 4 bytes, then FLIPPED it again to get back to the start.  That second flip made NIO see my buffer as 4 bytes long instead of however long it really was.  I just switched the method call from a .flip() to a .rewind() and it works beautifully now (turns out NIO DOES buffer un-read data for TCP socket channels).  Roll Eyes

Quack!  I'm a duck!

"Or make your own RationalNumber class (unless you need irrational numbers, then you're screwed )." - shmoove
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2005-12-15 15:26:59 »

Don't forget to remove() your SelectionKey from the Iterator after each next()

You have to "consume" the "events".

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Pippogeek (36 views)
2014-09-24 16:13:29

Pippogeek (29 views)
2014-09-24 16:12:22

Pippogeek (18 views)
2014-09-24 16:12:06

Grunnt (41 views)
2014-09-23 14:38:19

radar3301 (24 views)
2014-09-21 23:33:17

BurntPizza (60 views)
2014-09-21 02:42:18

BurntPizza (30 views)
2014-09-21 01:30:30

moogie (35 views)
2014-09-21 00:26:15

UprightPath (49 views)
2014-09-20 20:14:06

BurntPizza (52 views)
2014-09-19 03:14:18
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!