Interface NioServer.Listener

All Superinterfaces:
java.util.EventListener
All Known Implementing Classes:
NioServer.Adapter
Enclosing class:
NioServer

public static interface NioServer.Listener
extends java.util.EventListener

An interface for listening to events from a NioServer. A single NioServer.Event is shared for all invocations of these methods.

Of critical importance are the input and output buffers, as provided by NioServer.Event.getInputBuffer() and NioServer.Event.getOutputBuffer(). Below is a table describing the significance of the input and output buffers upon entering and exiting the listener's events.

EventInput outBuff upon entering eventOutput outBuff upon exiting event
New connection received null NA

This code is released into the Public Domain. Since this is Public Domain, you don't need to worry about licensing, and you can simply copy this NioServer.java file to your own package and use it as you like. Enjoy. Please consider leaving the following statement here in this code:

This NioServer class was copied to this project from its source as found at iHarder.net.

Author:
Robert Harder, rharder@users.sourceforge.net
See Also:
NioServer, NioServer.Adapter, NioServer.Event

Method Summary
 void connectionClosed(NioServer.Event evt)
          Called when a TCP connection is closed.
 void newConnectionReceived(NioServer.Event evt)
          Called when a new connection is received.
 void tcpDataReceived(NioServer.Event evt)
          Called when TCP data is received.
 void tcpReadyToWrite(NioServer.Event evt)
          Fired when a TCP channel is ready to be written to.
 void udpDataReceived(NioServer.Event evt)
          Called when UDP data is received.
 

Method Detail

newConnectionReceived

void newConnectionReceived(NioServer.Event evt)

Called when a new connection is received. The SelectionKey associated with the event (with OP_READ interest), is the accKey that will be used with the data received event. In this way, you can seed a Map or other data structure and associate this very accKey with the connection. You will only get new connection events for TCP connections (not UDP).

The accKey's attachment mechanism is unused by NioServer and is available for you to store whatever you like.

If your protocol requires the server to respond to a client upon connection, this sample code demonstrates such an arrangement being careful not to instantiate objects at each event:

   private CharsetEncoder encoder = Charset.forName("US-ASCII");
   private CharBuffer greeting = CharBuffer.wrap("Greetings\r\n");
   ...
   public void newConnectionReceived(NioServer.Event evt) {
       ByteBuffer outBuff = evt.getOutputBuffer();
       outBuff.clear();
       greeting.rewind();
       encoder.reset().encode( greeting, outBuff, true );
       outBuff.flip();
   }
 

Parameters:
evt - the shared event

tcpDataReceived

void tcpDataReceived(NioServer.Event evt)

Called when TCP data is received. Retrieve the associated ByteBuffer with NioServer.Event.getInputBuffer(). This is the source ByteBuffer used by the server directly to receive the data. It is a "direct" ByteBuffer (created with ByteBuffer.allocateDirect(..)).

Read from it as much as you can. Any data that remains on or after the value of position() will be saved for the next time an event is fired. In this way, you can defer processing incomplete data until everything arrives.

If you leave the buffer full, all the way up to the very last byte at capacity(), then that connection cannot receive any more data. On some operating systems and Java virtual machines, this will serve to throttle back the client sending the data.

The accKey's attachment mechanism is unused by NioServer and is available for you to store whatever you like.

If you wish to also write data as a result of what is read, the preferred method is to retrieve the output buffer with NioServer.Event.getOutputBuffer() and write bytes there, leaving the buffer in a ready-to-read state:

       ByteBuffer buff = evt.getOutputBuffer();       // Reuse it since it's already allocated
       buff.clear();                                  // Prepare outBuff for writing
       buff.putLong( System.currentTimeMillis() );    // Store data
       buff.flip();                                   // Put outBuff in "read me from here" mode
 

To make a trivial "echo" program, simple copy the contents of the input buffer to the output buffer:

 NioServer ns = new NioServer();
 ns.addNioServerListener(new NioServer.Adapter(){
      public void tcpDataReceived(NioServer.Event evt) {
          ByteBuffer inBuff = evt.getInputBuffer();
          ByteBuffer outBuff = evt.getOutputBuffer();
          outBuff.clear();
          outBuff.put(inBuff);
          outBuff.flip();
      }
 });
 

Parameters:
evt - the shared event

udpDataReceived

void udpDataReceived(NioServer.Event evt)

Called when UDP data is received. Retrieve the associated ByteBuffer with NioServer.Event.getInputBuffer(). This is the source ByteBuffer used by the server directly to receive the data. It is a "direct" ByteBuffer (created with ByteBuffer.allocateDirect(..)). The contents of the ByteBuffer will be the entire contents received from the UDP datagram. If you leave data in the output buffer (NioServer.Event.getOutputBuffer()), the server will attempt to send a UDP reply to the IP and port specified as the source IP and port in the datagram. Your firewall mileage may vary.

Parameters:
evt - the shared event

tcpReadyToWrite

void tcpReadyToWrite(NioServer.Event evt)

Fired when a TCP channel is ready to be written to. The preferred way to write is to leave data in the output buffer (NioServer.Event.getOutputBuffer()) attached to the event. The server will take care of sending it even if it can't all be sent at once (perhaps a slow network connection).

Here is an example of how to write to the channel:

   public void tcpReadyToWrite(NioServer.Event evt) {
       ByteBuffer buff = evt.getOutputBuffer();       // Reuse it since it's already allocated
       buff.clear();                                  // Prepare outBuff for writing
       buff.putLong( System.currentTimeMillis() );    // Store data
       buff.flip();                                   // Put outBuff in "read me from here" mode
   }

You can also just retrieve the accKey's channel, cast it to a SocketChannel and write to it that way, but you risk stalling the whole server if you're writing large amounts of data over a slow connection. Plus if there is data leftover from an earlier write via the output buffer, then you risk writing your data out of sequence.

Be aware of how large the output buffer is. You can change the output buffer size that the server uses with the NioServer.setOutputBufferSize(int) method, but that will not take effect until the server has finished processing the current set of selected SelectionKeys.

Parameters:
evt - the shared event

connectionClosed

void connectionClosed(NioServer.Event evt)
Called when a TCP connection is closed.

Parameters:
evt - the shared event