Skip to content

Instantly share code, notes, and snippets.

@MaZderMind
Last active March 27, 2020 15:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MaZderMind/0be1dea275ea25b39dc753583d742851 to your computer and use it in GitHub Desktop.
Save MaZderMind/0be1dea275ea25b39dc753583d742851 to your computer and use it in GitHub Desktop.
Example of a Nonblokcing Socket-Server with java.nio which reads Input Line-by-Line.
package de.mazdermind;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
public class ConnectionHandler {
private static final ByteBuffer REUSABLE_BYTE_BUFFER = ByteBuffer.allocate(1024);
private static final CharBuffer REUSABLE_CHAR_BUFFER = CharBuffer.allocate(1024);
private final CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
private final CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
private final SegmentedBuffer segmentedBuffer = new SegmentedBuffer();
public void read(SocketChannel client) throws IOException {
REUSABLE_BYTE_BUFFER.clear();
boolean eof = client.read(REUSABLE_BYTE_BUFFER) == -1;
REUSABLE_BYTE_BUFFER.flip();
System.out.println(String.format("read %d bytes to byte-buffer", REUSABLE_BYTE_BUFFER.limit()));
CoderResult decodeResult;
do {
REUSABLE_CHAR_BUFFER.clear();
decodeResult = decoder.decode(REUSABLE_BYTE_BUFFER, REUSABLE_CHAR_BUFFER, false);
REUSABLE_CHAR_BUFFER.flip();
System.out.println(String.format("decoded %d chars from byte-buffer", REUSABLE_CHAR_BUFFER.length()));
segmentedBuffer.put(REUSABLE_CHAR_BUFFER);
} while (decodeResult == CoderResult.OVERFLOW);
if (eof) {
segmentedBuffer.flush();
}
while (segmentedBuffer.hasNext()) {
String line = segmentedBuffer.next().trim();
if (line.equals("quit")) {
throw new ClosedChannelException();
}
String responseMessage = "echo >" + line + "<\n";
client.write(encoder.encode(CharBuffer.wrap(responseMessage)));
System.out.println(String.format("extracted line: >%s<", line));
}
if (eof) {
throw new ClosedChannelException();
}
}
}
package de.mazdermind;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Main {
public static void main(String[] args) throws IOException {
String bind = "0.0.0.0";
int port = 9999;
System.out.println(String.format("Starting Server on %s:%d", bind, port));
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress(bind, port));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
//noinspection InfiniteLoopStatement
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
SocketChannel client = serverSocket.accept();
System.out.println(String.format("Incoming Connection from %s", client.getRemoteAddress()));
client.configureBlocking(false);
SelectionKey newKey = client.register(selector, SelectionKey.OP_READ);
newKey.attach(new ConnectionHandler());
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ConnectionHandler connectionHandler = (ConnectionHandler) key.attachment();
try {
connectionHandler.read(client);
} catch (ClosedChannelException e) {
System.out.println(String.format("Connection from %s closed", client.getRemoteAddress()));
key.cancel();
client.close();
}
}
iter.remove();
}
}
}
}
package de.mazdermind;
import java.util.Iterator;
public class SegmentedBuffer implements Iterator<String> {
private final String terminator;
private String buffer = "";
private boolean isFlushing = false;
public SegmentedBuffer() {
this("\n");
}
public SegmentedBuffer(String terminator) {
this.terminator = terminator;
}
public void put(CharSequence charSequence) {
buffer += charSequence;
}
public void flush() {
isFlushing = buffer.length() > 0;
}
@Override
public boolean hasNext() {
return isFlushing || buffer.contains(terminator);
}
@Override
public String next() {
if (isFlushing) {
isFlushing = false;
String line = buffer;
buffer = "";
return line;
}
int index = buffer.indexOf(terminator);
String line = buffer.substring(0, index);
buffer = buffer.substring(index + 1);
return line;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment