libp2p streams are full-duplex. Each party can read and write simultaneously on the conduit, and the underlying transport guarantees (or not) delivery, while the multiplexer also participates in congestion control. Yamux, for example, applies stream-scoped congestion control to curtail head-of-line blocking in some circumstances. Mplex is more simplistic and relies purely on TCP congestion control.
There's an active debate in go-libp2p to rethink the single Close() method
