NIO networking as simple as it gets
Over the last months, I made some major improvements to my ‘NIO Wrapper’. I believe this is as simple as it gets. You get notified of I/O event via a callback mechanism, so you can act on ‘client connected’ or ‘data received from client’ events. The API is single-threaded (and immediately throws exceptions if used otherwise), regardless of how many servers are listening, and how many clients are connected (as this is the point on NIO).
The API does not force any protocol on you, so the received byte[]
s can be of any size, just how the OS received them. You can register ReadCallbacks, which cause you to be notified when a specified amount of bytes are received:
How to process incoming data: ReadCallback
NioClient client = ...; byte[] fill = new byte[N]; ReadCallback callback = new ReadCallback(fill) { public void done() { byte[] filled = this.data(); } }; callback.register(client);
How to send data:
client.enqueue(byte[]); // will combine your data, and send it in batches, whenever the OS feels like it
How to process incoming data even easier: PacketCallback (2 byte length header + payload)
NioClient client = ...; PacketCallback callback = new PacketCallback() { public void received(byte[] payload) { // we got yet another packet! NioClient source = this.client(); } }; callback.loop(client); // will infinitely register itself on this client
How to send data even easier: (using Packets)
Packet p = new Packet(byte[]); p.sendTo(clientA); p.sendTo(clientB); // prepends payload with 2b header and enqueues the write
Download it here: (source included)
www.indiespot.net/files/jawnae-net2b.jar
To connect to a server: (previously: Socket)
`
NioNetwork network = new NioNetwork(handler);
network.connect(new InetSocketAddress(HOST, PORT));
while (true)
{
network.select();
}
`
To listen for clients: (previously: ServerSocket)
`
NioNetwork network = new NioNetwork(handler);
network.listen(new InetSocketAddress(HOST, PORT));
while (true)
{
network.select();
}
`
NioNetworkHandler (you will implement this to handle all events)
`
public interface NioNetworkHandler
{
public void selectedKeys(int count);
public void selectFailure(IOException cause);
public void serverSelected(NioServer server);
public void clientSelected(NioClient client);
public void acceptedClient(NioClient client);
public void connectedClient(NioClient client);
public void unconnectableClient(NioClient client);
public void droppedClient(NioClient client, IOException cause);
public void disconnectedClient(NioClient client);
public void receivedData(NioClient client, int bytes);
public void sendingData(NioClient client);
public void sentData(NioClient client, int bytes);
public void executingTask(Runnable task);
public void taskCrashed(Runnable task, Throwable cause);
}
`
Ofcourse these are also provided for convenience:
NioNetworkAdapter, NioNetworkLogger, NioNetworkExtendableHandler
Executing tasks on the NetworkThread
All reads and writes must be performed on the NetworkThread. This is the thread on which the NioNetwork instance was constructed. Now you probably have more threads in your app, so what to do when you need to send a client a message at some random moment?
`
NioNetwork network = …;
NioServer server = …;
// on another thread:
Runnable broadcastTask = new Runnable()
{
public void run()
{
byte[] payload = …;
Packet packet = new Packet(payload);
for(NioClient client: server) // NioServer implements Iterable and returns all NioClients
{
packet.sendTo(client);
}
}
};
network.scheduleOnNetworkThread(broadcastTask);
network.interrupt(); // network.select() will unblock
`
Feedback greatly appreciated. Even if you mention MINA…