I'm trying to wait on multiple socket channels for data to read. I've copied example code from the web but it's not working for me. The problem is that the "select" call properly blocks until the first data is received, but thereafter immediately returns 0 (not ready). My code (for a single channel) follows.
final String HOST = "<REDACTED>.com";
final int PORT = 2000;
SocketChannel MyChannel;
Selector MySelector;
void doSelect()
{
SelectionKey key;
int nready;
long nr;
try {
ByteBuffer bytebuf = ByteBuffer.allocate( 1024 ); // allocate bytebuffer
InetSocketAddress addr = new InetSocketAddress( HOST, PORT); // form addr
MyChannel = SocketChannel.open(); // create socketchan
MyChannel.connect( addr ); // connect to data src
while( !MyChannel.finishConnect() ) Thread.sleep( 1000 ); // wait til connected
MyChannel.configureBlocking( false ); // set non-blocking
MySelector = Selector.open(); // open new selector
key = MyChannel.register( MySelector, SelectionKey.OP_READ ); // register for reads
while( true ) { // loop forever
nready = MySelector.select(); // block til something ready
if( nready <= 0 ) { // nothing ready?
logit( "not ready: select returned "+nready );
MyChannel.close();
break; // give up
}
if( key.isReadable() ) { // readable?
nr = MyChannel.read( bytebuf ); // read data
logit( "read "+nr+" bytes" );
}
} // end while
} // end try
catch( Exception e ) {
logit( "doSelect: "+e );
return;
}
}
//@ Log a message to logcat
void logit(String msg) { Log.i( "MYAPP", msg ); }
UPDATE 10/19/2019
Based on a suggestion by @user207421, I modified the code to iterate over selected key. This made no difference. The select() call is still not blocking after the first reception and the read from the channel says 0 bytes read..
Excerpt from the new code (some variables renamed for (my) readability)
while( true ) { // loop forever
nready = selector.select(); // call select: block til something ready
if( nready <= 0 ) { // nothing ready? (should never happen)
break; // give up
}
// PROCESS ALL SELECTED KEYS
Set<SelectionKey> selected = selector.selectedKeys(); // get selected key set
Iterator<SelectionKey> iter = selected.iterator(); // create iterator
while( iter.hasNext() ) { // while has more
key = iter.next(); // get next key
if( key.isReadable() ) { // check if ready to read
nr = chan.read( bb ); // read from channel
if( nr > 0 ) { // got some data?
printByteBuffer( bb );
}
else {
// should never happen! (but it does)
}
}
else if( key.isWritable()) {} // never happens!
else if( key.isAcceptable()) {} // never happens!
else if( key.isConnectable()) {} // never happens!
iter.remove();
} // end while hasnext
} // end while
//@ Convert ByteBuffer to byte array and print
void printByteBuffer(
ByteBuffer bb ) // BB to print
{
int nrem;
byte[] bytes;
String str;
bb.flip(); // reset position
nrem = bb.remaining();
bytes = new byte[nrem]; // alloc byte array
bb.get( bytes ); // get bytes from bytebuf
str = new String( bytes ); // cnvt to string
log( "received \""+str+"\"" );
}
Any suggestions greatly appreciated.
I found the solution based on a comment. Apparently the ByteBuffer was "full". I fixed the problem by issuing a ".clear()" on it just before the channel read().
I don't understand why this was necessary because the ByteBuffer was way bigger (1000 bytes) than any received data, but nontheless this works.
Re: blocking mode: Every example I found on the web said the channel should be set to non-blocking for Selector select() to work properly. I briefly tried blocking mode anyway but no joy with that.