The low-level way of handling this sort of thing is to setup all your IO (including the terminal input) as non-blocking, and then use select to dispatch code whenever input arrives or output is flushed at a socket/handle, and possibly do other stuff in between.