Switch to using IO.select for async IO reading

IO.select is what pretty much every single async IO library is using,
so it ought to be good enough for us as well. Since IO.select is a
syscall, we need actual IOs with file descriptors in order to test it,
so I set up a "fake socket" class that is somewhat misnamed, since it
sets up perfectly working sockets.