Add a `Socket` interface.
Use a read deadline instead of `time.AfterFunc`.

This avoids spawning an extra goroutine per connection, and makes it
easier to test the worker run loop.
Initial worker tests.