I’ve already read them several times, as well as the whole:
http://forum.java.sun.com/thread.jspa?threadID=459338&start=60&tstart=0
My problem is fairly simpel but I can’t seem to find a solution:
I want a simple chat server where, when a client sends a message, every client gets this message.
I have experimented with incoming, outgoing queues…complicating things with each try. There has to be a good solution but I can’t figure out which one. Until now, I came up with this:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.*;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
public class Server {
// HashMap where we store the ByteBuffer of each SelectionKey
public HashMap out_buffers = new HashMap();
public ArrayList keys = new ArrayList();
public ArrayList messages = new ArrayList();
Charset charset = Charset.forName("ISO-8859-1"); // England and most of
// Europe
public Server(int port) throws IOException {
System.out.println("Start init.");
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address);
ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Finished init: listening on port " + port);
for (;;) {
// Selector.select() is blocking
int num = selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
it.remove();
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
// new Connection
System.out.println("New incoming connection.");
SocketChannel newsc = ((ServerSocketChannel) key.channel())
.accept();
newsc.configureBlocking(false);
SelectionKey selectKey = newsc.register(selector,
SelectionKey.OP_READ);
// create a bytebuffer for this SelectionKey
keys.add(selectKey);
out_buffers.put(selectKey, ByteBuffer.allocate(512));
} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
SocketChannel newsc = (SocketChannel) key.channel();
// we use the SelectionKey to get the buffer
String message = new String();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesEchoed = 0;
while (true) {
buffer.clear();
int r = -1;
try {
r = newsc.read(buffer);
} catch (IOException e) {
System.out.println("Client closed connection.");
}
if (r <= 0) {
if (r == -1) {
// the client has disconnected
newsc.close();
keys.remove(key);
}
break;
}
buffer.flip();
message = message.concat(charset.decode(buffer)
.toString());
messages.add(message);
}
if(message.length() != 0)
System.out.println("Message received:" + message);
for (int i = 0; i < keys.size(); i++) {
SelectionKey tmpkey = (SelectionKey) keys.get(i);
out_buffers.put(tmpkey, charset.encode(message));
tmpkey.channel().register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE );
}
} else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
//System.err.println("Ready for write");
SocketChannel newsc = (SocketChannel) key.channel();
ByteBuffer out = (ByteBuffer)out_buffers.get(key);
newsc.write(out);
if (!out.hasRemaining()){
key.channel().register(selector, SelectionKey.OP_READ);
out_buffers.remove(key);
}
} else {
System.err.println("Unknown key type");
}
}
}
}
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Usage: java Server port");
} else {
try {
new Server(Integer.parseInt(args[0]));
} catch (NumberFormatException e) {
System.out.println("Portnumber must be an integer.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}