0

I've been looking into java.nio's asynchronous capabilities, and so far I am a fan of the AsynchronousByteChannel class, as it lets me provide completion callbacks for each read or write operation. This adapts well with scala's Future class.

Now I'm trying to interact with a DatagramChannel asynchronously. (As a matter of curiosity, I'm trying to implement my own torrent client, and some trackers use UDP.)

My goal right now is to find a means to adapt the current read and write methods from their original signatures...

def write(src: ByteBuffer): Int
def read(dest: ByteBuffer): Int

to a scala-futures-oriented signature like...

def write(src: ByteBuffer): scala.concurrent.Future[Int]
def read(dest: ByteBuffer): scala.concurrent.Future[Int]

Looking into the API and finding examples online, and found my way to the Selector class. As far as I can tell, that's what I need to use to make a DatagramChannel be "non-blocking", but I see three methods that seem relevant:

select() - blocks until a selection is ready
select(timeout) - blocks until either a selection is ready or timeout is reached
selectNow - doesn't block, but is useless if called before a selection is ready

So it appears my choices for "non-blocking" are either to block (wtf?) or to occupy a thread that runs a busy loop that repeatedly calls one of the select methods. This is my problem.

Is there a way to achieve true non-blocking IO using a DatagramChannel? If not, what is the best way to handle (read 'minimize') the actual blocking?

Dylan
  • 13,645
  • 3
  • 40
  • 67
  • If at all possible, you should look into using Netty (http://netty.io/) instead of trying some of the lower level (and complicated) NIO code yourself. Netty is all async, so that should line up well with completing Promises that other pieces of code are waiting on for completion. – cmbaxter Jun 14 '13 at 13:01
  • @cmbaxter That may be fine in the long run, but right now I'm more interested in learning what goes on "under the hood". When I get a chance I'll go check out some of their source code. – Dylan Jun 14 '13 at 13:47
  • I did a little looking around on this. The I/O itself (read/write) is still completely non-blocking, but the select itself is not. So if there is no channel available to select, the thread performing the selection will block. But once a channel is available and is selected, the read/writes will be completely non-blocking. If this is sufficient, let me know and I will add as an answer. – cmbaxter Jun 14 '13 at 14:05
  • @cmbaxter It sounds like you've arrived at the same place as I did before I posted the question. My main complaint is that I have to interact with a blocking API, as opposed to `Selector` providing some "callback" mechanism. If there is in fact no way around that, then please do post an answer regarding the best way to use the Selector – Dylan Jun 14 '13 at 14:21

1 Answers1

0

Exploiting a dedicated selector thread is not a problem at all. First, it is unavoidable. Second, AsynchronousByteChannel implementations also use background threads under the hood.

As for the best way to use Selector, I believe I found one in the SelectorThread implementation (note it is still in the "work" branch). I did not try it with DatagramChannel, but it should work: just implement AsyncDatagramChannel the same way as AsyncSocketChannel1.

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38