IMO, you're going to cause more pain than needed for using multiple threads for each client's connection, and for little (if any) benefit.
You could create 1 thread to handle all client connections, and just check all the clients sockets with select, or, you could treat the client connections portion as you would any other part of a typical game loop update:
int clientsReady = select(NumClients, &ClientFDs, NULL, NULL, &timeout);
if (clientsReady > 0) {
// process the clients
}
else if (clientsRead == -1) {
// handle error
}
numClients is a bit wrong here. The first argument shall not be the number of fds in your fdset but the number of the highest fd to check + 1.
http://linux.die.net/man/2/select
nfds is the highest-numbered file descriptor in any of the three sets, plus 1.
Its also worth mentioning that ClientFDs and timeout should be reinitialized after select.
To answer the question:
Go for async IO and use select/kqueue/poll or whatever else you like. select is pretty easy to use , even tho a bit confusing at first. especially if you want to to asyncronous write operations as well or add fds from files to your select queue to do asynchronous file access to the OS. But i know from back in the days that UOX2 (a very famous Ultima Online freeshard) was coded with select and ran great. Later one they added threads etc to leverage level loading and other stuff but in the beginning everything was one thread and async IO. I think thats anyway the way to go for online rpgs. You should just take care not to do put too much stuff in each cycle of the main loop. But thats where sharding comes into the picture. For example, Ultima Online (the real one), had multiple servers per world.