- Netty at https://netty.io/
- Apache MINA at http://mina.apache.org/
The above implementations/frameworks have gone way past the point of being just "NIO Socket Servers". They are in fact fully evolved event based asynchronous systems you can use for a wide variety of needs.
Let's get down to business then, The following implementation simulates a request-reply.
The server simply listens for connections on a port and responds to valid requests with a reply.
The server simply listens for connections on a port and responds to valid requests with a reply.
package com.sockets.server; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Date; public class ProcessSocketChannel implements Runnable { private SocketChannel socketChannel; private int BUFFER_SIZE = 1024; public ProcessSocketChannel(SocketChannel socketChannel) { this.socketChannel = socketChannel; Thread thread = new Thread(this); thread.start(); } public void run() { System.out.println("Connection received from " + socketChannel.socket().getInetAddress().getHostAddress()); readMessage(); sendMessage("This is the server!!"); } void sendMessage(String msg) { String fullmessage = new Date().toString() + " > " + msg; ByteBuffer buf = ByteBuffer.allocate(fullmessage.getBytes().length); buf.clear(); buf.put(fullmessage.getBytes()); buf.flip(); while (buf.hasRemaining()) { try { socketChannel.write(buf); } catch (IOException e) { e.printStackTrace(); } } } void readMessage() { ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); Charset charset = Charset.forName("us-ascii"); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer; try { int bytes = socketChannel.read(byteBuffer); byteBuffer.flip(); charBuffer = decoder.decode(byteBuffer); String result = charBuffer.toString(); System.out.println(result); } catch (IOException e) { e.printStackTrace(); } finally { byteBuffer = null; charset = null; decoder = null; charBuffer = null; } } }
Processing of requests is delegated to a thread ProcessSocketChannel ,
package com.sockets.server; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Date; public class ProcessSocketChannel implements Runnable { private SocketChannel socketChannel; private int BUFFER_SIZE = 1024; public ProcessSocketChannel(SocketChannel socketChannel) { this.socketChannel = socketChannel; Thread thread = new Thread(this); thread.start(); } public void run() { System.out.println("Connection received from " + socketChannel.socket().getInetAddress().getHostAddress()); readMessage(); sendMessage("This is the server!!"); } void sendMessage(String msg) { String fullmessage = new Date().toString() + " > " + msg; ByteBuffer buf = ByteBuffer.allocate(fullmessage.getBytes().length); buf.clear(); buf.put(fullmessage.getBytes()); buf.flip(); while (buf.hasRemaining()) { try { socketChannel.write(buf); } catch (IOException e) { e.printStackTrace(); } } } void readMessage() { ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); Charset charset = Charset.forName("us-ascii"); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer; try { int bytes = socketChannel.read(byteBuffer); byteBuffer.flip(); charBuffer = decoder.decode(byteBuffer); String result = charBuffer.toString(); System.out.println(result); } catch (IOException e) { e.printStackTrace(); } finally { byteBuffer = null; charset = null; decoder = null; charBuffer = null; } } }
As for the client
package com.sockets.client; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Date; public class Client { //The default buffer size private final int BUFFER_SIZE = 1024; private SocketChannel clientSocket; //The port of the server connecting to private int port = 7777; void run() { try { clientSocket = SocketChannel.open(); //Obtaining the localhost InetAddress host = InetAddress.getLocalHost(); //Connecting to server clientSocket.connect(new InetSocketAddress(host, port)); System.out.println(String.format("Connected to %s on port %d", host.getHostAddress(), port)); //Sending a message to the server sendMessage("Hello Server!!"); //Reading the reply sent from the server readMessage(); } catch (UnknownHostException unknownHost) { System.err.println("You are trying to connect to an unknown host!"); } catch (IOException ioException) { ioException.printStackTrace(); } finally { //Closing connection try { clientSocket.close(); } catch (IOException ioException) { ioException.printStackTrace(); } } } void sendMessage(String msg) throws IOException { String fullmessage = new Date().toString() + " > " + msg; ByteBuffer buf = ByteBuffer.allocate(fullmessage.getBytes().length); //Initialize the buffer buf.clear(); buf.put(fullmessage.getBytes()); //Flip the content of the buffer before writing buf.flip(); //Writing Buffer Content to socket while (buf.hasRemaining()) { clientSocket.write(buf); } } void readMessage() { //Reads a text message ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); Charset charset = Charset.forName("us-ascii"); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer; try { int bytes = clientSocket.read(byteBuffer); byteBuffer.flip(); charBuffer = decoder.decode(byteBuffer); String result = charBuffer.toString(); System.out.println(result); } catch (IOException e) { e.printStackTrace(); } finally { byteBuffer = null; charset = null; decoder = null; charBuffer = null; } } public static void main(String args[]) { Client client = new Client(); client.run(); } }
While I admit that the above implementation is less than ideal, given that it captures the basics of socket communications, I think it's a good starting point for those who still care about how the clock actually ticks.