Refactor to use dispatch_io for tasks, and wait for EOF

Hopefully resolves #139, #135, #161.

/cc @joshaber @keithduncan
The docs say that “the system takes control of the file descriptor” until the channel is closed. After that, it appears you're on your own, and the descriptor may still be valid.

In any case, redundant `close()` calls won't hurt anything.