XNIO Quick Start

Quick Start: TCP

 

Using XNIO with TCP is simply a question of implementing the ChannelListener interface for a TcpChannel (or one of its superclasses).

 

TCP Server (XNIO 2)

 

Here's a simple TCP server which binds to port 12345, and which echos data back to any clients that connect to it.  It uses the non-blocking read, blocking-write pattern.

 

import org.jboss.xnio.Xnio;
import org.jboss.xnio.IoUtils;
import org.jboss.xnio.ChannelListener;
import org.jboss.xnio.OptionMap;
import org.jboss.xnio.TcpServer;
import org.jboss.xnio.channels.TcpChannel;
import org.jboss.xnio.channels.Channels;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.net.InetSocketAddress;

public final class SimpleEchoServer {

    public static void main(String[] args) throws Exception {
        final Xnio xnio = Xnio.create();

        // First define the listener that actually is run on each connection.
        final ChannelListener<TcpChannel> readListener = new ChannelListener<TcpChannel>() {
            public void handleEvent(final TcpChannel channel) {
                final ByteBuffer buffer = ByteBuffer.allocate(512);
                int res;
                try {
                    while ((res = channel.read(buffer)) > 0) {
                        buffer.flip();
                        Channels.writeBlocking(channel, buffer);
                    }
                    // make sure everything is flushed out
                    Channels.flushBlocking(channel);
                    if (res == -1) {
                        channel.close();
                    } else {
                        channel.resumeReads();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    IoUtils.safeClose(channel);
                }
            }
        };

        // Create an open listener.
        final ChannelListener<TcpChannel> openListener = new ChannelListener<TcpChannel>() {
            public void handleEvent(final TcpChannel channel) {
                // TCP channel has been accepted at this stage.
                channel.getReadSetter().set(readListener);
                // read listener is set; start it up
                channel.resumeReads();
            }
        };

        // Create the server.
        final TcpServer server = xnio.createTcpServer(openListener, OptionMap.EMPTY);

        // Bind it.
        server.bind(new InetSocketAddress(12345));
    }
}

 

Simple Blocking TCP Client (XNIO 2)

 

This illustrative example is to show the blocking API methods in use.

 

import org.jboss.xnio.Xnio;
import org.jboss.xnio.IoUtils;
import org.jboss.xnio.OptionMap;
import org.jboss.xnio.TcpConnector;
import org.jboss.xnio.FutureConnection;
import org.jboss.xnio.channels.TcpChannel;
import org.jboss.xnio.channels.Channels;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;

public final class SimpleHelloWorldBlockingClient {

    public static void main(String[] args) throws Exception {
        final Charset charset = Charset.forName("utf-8");
        final Xnio xnio = Xnio.create();
        try {
            final TcpConnector connector = xnio.createTcpConnector(OptionMap.EMPTY);
            final IoFuture<TcpChannel> futureConnection = connector.connectTo(new InetSocketAddress("localhost", 12345), null, null);
            final TcpChannel channel = futureConnection.get();
            try {
                // Send the greeting
                Channels.writeBlocking(channel, ByteBuffer.wrap("Hello world!\n".getBytes(charset)));
                // Make sure all data is written
                Channels.flushBlocking(channel);
                // And send EOF
                channel.shutdownWrites();
                System.out.println("Sent greeting string!  The response is...");
                ByteBuffer recvBuf = ByteBuffer.allocate(128);
                // Now receive and print the whole response
                while (Channels.readBlocking(channel, recvBuf) != -1) {
                    recvBuf.flip();
                    final CharBuffer chars = charset.decode(recvBuf);
                    System.out.print(chars);
                    recvBuf.clear();
                }
            } finally {
                IoUtils.safeClose(channel);
            }
        } finally {
            IoUtils.safeClose(xnio);
        }
    }
}

 

Note that this fully-blocking approach generally doesn't scale any better than plain sockets: if the remote side can't accept more data (because, for example the local side hasn't consumed any yet), you will be deadlocked with the remote side as they wait for you to read and you wait for them to read.  Since our greeting message is quite short, we can avoid filling up the OS socket buffers and sidestep the problem; were we to try a very large message of several kilobytes or more, we'd probably hit this issue.