I'd like to build a multi user dungeon in Java/C# (also open to other suggestions). Below I have listed two ways of handling connections, and would like to know which would be the recommended way?
I think a good way to build it would be something like this:
Currently, I'm working on the connection handling portion (shown in the picture on the left, heavy black rectangle). It would take care of the connection handling between multiple clients and basically shove commands received from clients (denoted by newline char) into a queue, which the game engine can then pull off of and process. If there is a reply, the game engine would shove it into another queue so the connection handler can send it back to the client.
I see two ways to work this part:
Thread per connection
class Server {
public void Listen() {
// configure
final int portNumber = 81;
try {
ServerSocket serverSocket = new ServerSocket(portNumber);
while (true) {
Socket socket = serverSocket.accept();
new ProcessThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ProcessThread extends Thread {
protected Socket socket;
public ProcessThread(Socket clientSocket) {
this.socket = clientSocket;
}
public void run() {
try {
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os, true);
while (true) {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = br.readLine();
// do processing here
}
}
}
}
Pros:
- Easier implementation
Cons:
- Thread per connection not scalable
- Multithreading = potential yuckiness
Async socket
public class Server {
// use hashmap to keep track of current input
private HashMap<SelectionKey, StringBuilder> strings = new HashMap<>();
public void Listen() {
// configure
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(256);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
// register new connection
register(selector, serverSocket);
}
if (key.isReadable()) {
// process input
// add input to hashmap, if not newline terminated
process(buffer, key);
}
iter.remove();
}
}
}
}
Pros:
- Will definitely process in order received
- Less resource intensive (?)
Cons:
- Handling readline is more difficult
What would be the recommended way?
I'm leaning towards the thread per connection, as it seems to be slightly easier to implement. For a MUD, I would expect less than 200 simultaneous connections (50 might be a more accurate estimate), which would not be too resource intensive.