I used IO :: Socket because I found the most examples out there, but I found it very difficult to understand how everything works with it.
Yes, the select(2) system call is (one of) the classic ways to do it. "Classic" both in the good and bad sense: good because understanding it will help you understand how lots of servers work and how things work on a lower level, not so good because nowadays I'd consider it fairly low level, so for just getting stuff done, as I said IMHO event loops are a good approach.