For my paid work, I'm currently putting together a little custom server application, in order to farm some processing out to another computer. Although I've been involved in large telecoms projects for a few years now, this is actually the first time that I've sat down and actually tried to use the sockets API directly. It's also the first time I've had to think seriously about how best to use multiple threads. It's quite fun, and nice when it works, though it took me a couple of days to figure out the nuances of select(), such as that you can add the listening socket to the list of sockets that you test for readableness, in order to detect whether it's ready to accept() a new connection.
I know about epoll too, but I'm stuck on Linux kernel 2.4, and suspect that it wouldn't have an advantage in this particular situation.
Reading Robert Love's book (which I'm still reading gradually) also made me have a mini epiphany about multithreading. For instance, the explanation of how the kernel handles keyboard interrupts. The kernel needs to quickly store the new data in the buffer, but doesn't need to block at that moment waiting for some more involved processing. So it defers the work to a “bottom half” that runs in a different process. That and other examples in the book help me to think a bit more clearly about what part of work must be done immediately, what can be done a bit later, and what can be done concurrently.