Abstract over NetworkStream using dynamic dispatch

Abstract out NetworkStream for testing and extensibility, but use dynamic
dispatch to maintain ergonomics and not have a flood of generics.

Server and client benchmarks show that this makes very little difference in
performance and using dynamic dispatch here is significantly more
ergonomic.

This also bounds NetworkStream with Send to prevent incorrect
implementations.

@seanmonstar I checkout out your branch, rebased current master,
and then made these changes.