separate out request_worker send functionality into send_worker. more info:

We don't want to block the originating threads that execute a send
as that would slow down requests if they all have to sync access
to a single socket.

Instead we have a lockless queue where send requests are pushed,
and then the send_worker is notified. The worker wakes up and pushes
all pending requests to the socket.

We have to manage reconnects, so there's still the need to sync access
to the socket which is shared with the receiving request_worker.
This is however only for set_socket() and queue_send() so thread
contention is kept to the minimum and sending is (mostly) lockfree.