Image for post
Image for post
Photo by Evi Radauscher on Unsplash

Java sockets I/O: blocking, non-blocking and asynchronous

Introduction

The POSIX definitions

I/O models

Blocking I/O model

blocking I/O model
blocking I/O model

Non-blocking I/O model

non-blocking I/O model
non-blocking I/O model

I/O multiplexing model

I/O multiplexing model
I/O multiplexing model

Signal-driven I/O model

signal-driven I/O model
signal-driven I/O model

Asynchronous I/O model

asynchronous I/O model
asynchronous I/O model

Java I/O APIs

Java IO API

Java NIO API

Java NIO2 API

Socket echo server

Blocking IO echo server

public class IoEchoServer {   public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7000);
while (active) {
Socket socket = serverSocket.accept(); // blocking
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
int read;
byte[] bytes = new byte[1024];
while ((read = is.read(bytes)) != -1) { // blocking
os.write(bytes, 0, read); // blocking
}
socket.close();
}
serverSocket.close();
}
}

Blocking NIO echo server

public class NioBlockingEchoServer {   public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress("localhost", 7000));
while (active) {
SocketChannel socketChannel = serverSocketChannel.accept(); // blocking
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
buffer.clear();
int read = socketChannel.read(buffer); // blocking
if (read < 0) {
break;
}
buffer.flip();
socketChannel.write(buffer); // blocking
}
socketChannel.close();
}
serverSocketChannel.close();
}
}

Non-blocking NIO echo server

public class NioNonBlockingEchoServer {   public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(7000));
while (active) {
SocketChannel socketChannel = serverSocketChannel.accept(); // non-blocking
if (socketChannel != null) {
socketChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
buffer.clear();
int read = socketChannel.read(buffer); // non-blocking
if (read < 0) {
break;
}
buffer.flip();
socketChannel.write(buffer); // can be non-blocking
}
socketChannel.close();
}
}
serverSocketChannel.close();
}
}

Multiplexing NIO echo server

public class NioMultiplexingEchoServer {   public static void main(String[] args) throws IOException {
final int ports = 8;
ServerSocketChannel[] serverSocketChannels = new ServerSocketChannel[ports];
Selector selector = Selector.open(); for (int p = 0; p < ports; p++) {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannels[p] = serverSocketChannel;
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress("localhost", 7000 + p));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}
while (active) {
selector.select(); // blocking
Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();
while (keysIterator.hasNext()) {
SelectionKey key = keysIterator.next();
if (key.isAcceptable()) {
accept(selector, key);
}
if (key.isReadable()) {
keysIterator.remove();
read(selector, key);
}
if (key.isWritable()) {
keysIterator.remove();
write(key);
}
}
}
for (ServerSocketChannel serverSocketChannel : serverSocketChannels) {
serverSocketChannel.close();
}
}
}
private static void accept(Selector selector, SelectionKey key) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverSocketChannel.accept(); // can be non-blocking
if (socketChannel != null) {
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
}
private static void read(Selector selector, SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer); // can be non-blocking
buffer.flip();
socketChannel.register(selector, SelectionKey.OP_WRITE, buffer);
}
private static void write(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment(); socketChannel.write(buffer); // can be non-blocking
socketChannel.close();
}

Asynchronous NIO2 echo server

public class Nio2CompletionHandlerEchoServer {   public static void main(String[] args) throws IOException {
AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(7000));
AcceptCompletionHandler acceptCompletionHandler = new AcceptCompletionHandler(serverSocketChannel);
serverSocketChannel.accept(null, acceptCompletionHandler);
System.in.read();
}
}
class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Void> {   private final AsynchronousServerSocketChannel serverSocketChannel;   AcceptCompletionHandler(AsynchronousServerSocketChannel serverSocketChannel) {
this.serverSocketChannel = serverSocketChannel;
}
@Override
public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
serverSocketChannel.accept(null, this); // non-blocking
ByteBuffer buffer = ByteBuffer.allocate(1024);
ReadCompletionHandler readCompletionHandler = new ReadCompletionHandler(socketChannel, buffer);
socketChannel.read(buffer, null, readCompletionHandler); // non-blocking
}
@Override
public void failed(Throwable t, Void attachment) {
// exception handling
}
}
class ReadCompletionHandler implements CompletionHandler<Integer, Void> {   private final AsynchronousSocketChannel socketChannel;
private final ByteBuffer buffer;
ReadCompletionHandler(AsynchronousSocketChannel socketChannel, ByteBuffer buffer) {
this.socketChannel = socketChannel;
this.buffer = buffer;
}
@Override
public void completed(Integer bytesRead, Void attachment) {
WriteCompletionHandler writeCompletionHandler = new WriteCompletionHandler(socketChannel);
buffer.flip();
socketChannel.write(buffer, null, writeCompletionHandler); // non-blocking
}
@Override
public void failed(Throwable t, Void attachment) {
// exception handling
}
}
class WriteCompletionHandler implements CompletionHandler<Integer, Void> {   private final AsynchronousSocketChannel socketChannel;   WriteCompletionHandler(AsynchronousSocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void completed(Integer bytesWritten, Void attachment) {
try {
socketChannel.close();
} catch (IOException e) {
// exception handling
}
}
@Override
public void failed(Throwable t, Void attachment) {
// exception handling
}
}

Conclusion

Written by

Senior Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store