users@grizzly.java.net

Re: Newbie question: Understanding CallbackHandler

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Thu, 20 Dec 2007 13:35:53 -0500

Salut,

CigarMan wrote:
> I have been trying to use Grizzly for the past couple of days to write an
> asynchronous TCP/UDP client. Basically, I want my client to write a bunch of
> bytes (request) to a remote server and eventually receive a response as a
> bunch of bytes.
>
> Looking at the unit tests available with Grizzly framework module, it looks
> like I have to write a callbackhandler to handle the asynchronous response.
> Unfortunately I don't understand the callbackHandler interface.
>
> In TCPAsynchQueueReaderTest.java, the method public void
> onConnect(IOEvent<Context> ioEvent) seems to register a key with the OP_READ
> event.
>
> ioEvent.attachment().getSelectorHandler().register(key,
> SelectionKey.OP_READ);
>
> First of all, I'm kind of lost to what that whole registration means, I have
> very little cue as to what this onConnect method is trying to achieve (I
> would really appreciate if you could post references on your websites so
> that new developpers can get the appropriate background knowledge before
> digging into your framework). I assume this has to do with having the
> selectionKey try to perform a read operation once a connection is
> established with the client.
>
> But yet in the same example, the onRead and onWrite method do nothing!

You should take a look at the TCPConnectorHandler/UDPConnectorHandler as
a starter. They allow you to read/write bytes easily.

>
> Basically, as a user, I need to know where can I put my application code
> that will get the bytes received and perform my business logic (I would
> really like to understand how to write a callbackhandler! :.).

Right. The CallBackHandler is exactly what you need to customize and set
on the ConnectorHandler. As a very simple example:

> private final CallbackHandler createTCPCallbackHandler
> (final ConnectorHandler connectorHandler, final TargetTuple tt){
> CallbackHandler<Context> callbackHandler = new CallbackHandler<Context>() {
>

Below is the onConnect implementation that you can use as it is.

> public void onConnect(IOEvent<Context> ioEvent) {
> SelectionKey key = ioEvent.attachment().getSelectionKey();
> connectorHandler.finishConnect(key);
> controller.registerKey(key, SelectionKey.OP_READ,
> Controller.Protocol.TCP);
> }
>

The onRead will be called when bytes are available.

> public void onRead(IOEvent<Context> ioEvent) {
> try {
> Context ctx = ioEvent.attachment();
> SelectionKey key = ctx.getSelectionKey();
> if (!key.isValid()) {
> return;
> }
>
> // disable OP_READ on key before doing anything else
> key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
                          // READ bytes
                          ((SocketChannel)key.channel()).read(ByteBuffer)
                         // Do something with the bytes

> }
> }
>

the onWrite will be invoked when bytes are available.

> public void onWrite(IOEvent<Context> ioEvent) {
                        // Write your bytes
                      ((SocketChannel)key.channel()).write(ByteBuffer)

> }
> };
> return callbackHandler;
> }

So a simple snipet would consist of:

TCPConnectorHandler mtCh = new TCPConnectorHandler();
mtCh.setCallbackHandler(new MyCallBackHandler());
mtCh.connect(...);

...

mtCh.read(ByteBuffer, true);

...

mtCh.write(ByteBuffer, true);


Here you will use a special read/write functionality Grizzly is
offering, which is to read/write bytes using a temporary Selector pool.
It behave the same way as blocking IO, but using non-blocking IO under
the hood, giving great performance.

>
> Is there a higher level API provided with the Grizzly framework for writing
> basic clients and servers that send bytes over TCP/UDP (not HTTP)?

The TCPConnectorHandler/UDPConnectorHandler is the place to start. Have
you see this blog:

Yes our documentation is really bad...we are working to fix the problem.

>
> Also, one last question (for now :.), do I need a protocol filter on the
> server side if every write operation write operation from the client writes
> a full request to the channel? (Sorry, I don't really understand behind the
> rationale of the protocolfilter, I don't really understand what kind of
> issue it addresses.

Since you only need client side component, you don't need to use
ProtocolFilter/ProtocolChain. You usually use them when you write a
server side component, or you use a protocol (like SIP) where a client
can becomes a server, and vice versa.

For now, let's work on the TCPConnectorHandler/UDPConnectorHandler.


>
>
> Thanks for your help,
>
>
> Simon
>
>
> P.S.: Don't hesitate to write back in french if you feel like it, I'm from
> Montreal.

Hey hey :-)

>
> Once I get a better understanding of how to write a basic Grizzly asynch
> client and server, I will try to write a tutorial for newbies (like myself)
> about it. I'll let you know.

That would be great!!!

Thanks

-- Jeanfrancois