- 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.
