4. Serve one client with each server thread
... and let read() and write() block. Has the disadvantage of using a whole stack
frame for each client, which costs memory. Many OS's also have trouble handling more
than a few hundred threads. If each thread gets a 2MB stack (not an uncommon
default value), you run out of *virtual memory* at (2^30 / 2^21) = 512 threads
on a 32 bit machine with 1GB user-accessible VM (like, say, Linux as normally shipped on x86).
You can work around this by giving each thread a smaller stack,
but since most thread libraries don't allow growing thread stacks
once created, doing this means designing your program to minimize
stack use. You can also work around this by moving to a 64 bit processor.
The thread support in Linux, FreeBSD, and Solaris is improving,
and 64 bit processors are just around the corner even for mainstream users.
Perhaps in the not-too-distant future, those who prefer using
one thread per client will be able to use that paradigm even
for 10000 clients.
Nevertheless, at the current time, if you actually want to support that many clients,
you're probably better off using some other paradigm.
For an unabashedly pro-thread viewpoint, see
Why Events Are A Bad Idea (for High-concurrency Servers)
by von Behren, Condit, and Brewer, UCB, presented at HotOS IX.
Anyone from the anti-thread camp care to point out a paper that rebuts this one? :-)

