I am learning Java's NIO and as an exercise, I have implemented a simple chat server. I would like to ask if I am using NIO's features in the correct way.
public class ChatServer implements Runnable {
private static final int BUFFER_SIZE = 256;
private static final int DEFAULT_PORT = 10523;
private static final String WELCOME_MESSAGE = "Welcome to NioChat!\n";
private final int mPort;
private ServerSocketChannel mServerChannel;
private Selector mSelector;
private ByteBuffer mBuffer = ByteBuffer.allocate(BUFFER_SIZE);
private final ByteBuffer mWelcomeBuffer = ByteBuffer.wrap(WELCOME_MESSAGE
.getBytes());
public ChatServer(int port) throws IOException {
mPort = port;
mServerChannel = ServerSocketChannel.open();
mServerChannel.socket().bind(new InetSocketAddress(port));
mServerChannel.configureBlocking(false);
mSelector = Selector.open();
mServerChannel.register(mSelector, SelectionKey.OP_ACCEPT);
}
public static void main(String[] args) throws IOException {
ChatServer server = new ChatServer(DEFAULT_PORT);
new Thread(server).start();
}
@Override
public void run() {
try {
System.out.println("Server started on port " + mPort);
Iterator<SelectionKey> iter;
SelectionKey key;
while (mServerChannel.isOpen()) {
mSelector.select();
iter = mSelector.selectedKeys().iterator();
while (iter.hasNext()) {
key = iter.next();
iter.remove();
if (key.isAcceptable())
handleAccept(key);
if (key.isReadable())
handleRead(key);
}
}
} catch (IOException e) {
System.out.println("IOException, server on port " + mPort
+ " terminating. Stack trace:");
e.printStackTrace();
}
}
private void handleAccept(SelectionKey key) throws IOException {
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
String address = (new StringBuilder(sc.socket().getInetAddress()
.toString())).append(":").append(sc.socket().getPort())
.toString();
sc.configureBlocking(false);
sc.register(mSelector, SelectionKey.OP_READ, address);
sc.write(mWelcomeBuffer);
mWelcomeBuffer.rewind();
System.out.println("Accepted connection from: " + address);
}
private void handleRead(SelectionKey key) throws IOException {
SocketChannel ch = (SocketChannel) key.channel();
StringBuilder sb = new StringBuilder();
mBuffer.clear();
int read = 0;
while ((read = ch.read(mBuffer)) > 0) {
mBuffer.flip();
byte[] bytes = new byte[mBuffer.limit()];
mBuffer.get(bytes);
sb.append(new String(bytes));
mBuffer.clear();
}
String msg;
if (read < 0) {
msg = key.attachment() + " left the chat.\n";
ch.close();
} else {
msg = key.attachment() + ": " + sb.toString();
}
System.out.println(msg);
broadcast(msg);
}
private void broadcast(String msg) throws IOException {
ByteBuffer messageBuffer = ByteBuffer.wrap(msg.getBytes());
for (SelectionKey key : mSelector.keys()) {
if (key.isValid() && key.channel() instanceof SocketChannel) {
SocketChannel channel = (SocketChannel) key.channel();
channel.write(messageBuffer);
messageBuffer.rewind();
}
}
}
}