It took me a long time to realize that marshal/unmarshal functions should not operate on streams. You're just translating to/from an object in memory anyway, so the unbounded nature of streams doesn't buy you anything.
Buffers are also nice for unmarshalling, because they force you to frame your messages with their size; consequently, you'll know up front how large of an object to expect, and can abort if it's too large. Plus you can read the whole object in one syscall, another performance win