
Maxim Yegorushkin wrote:
... And too slow. You have one data copy from kernel into the streambuf, and another one from the streambuf to the message object. The same is for output: message -> streambuf -> socket. This is unacceptable, at least for the kind of software I build.
For example, I had a router which used a TCP binary protocol. Each message is prefixed with 4 byte length, so I read the 4 bytes, resized a std::vector<char> for the message length, and then read the message into the vector. After profiling the router under heavy load it turned out that 30% of user time was spent in guess where? In zeroing out memory in std::vector<char>::resize(). And you are talking about data copying here...
Considering the protocol of your application has built in methods for announcing the length of the payload, your requirement is met by the streambuf::sgetn(char_type*, streamsize) method, for a properly specialized implementation of the virtual protected xsgetn method. A streambuf manipulated solely by sgetn and sputn won't ever fill internal buffers. By encapsulating your protocol message inside a protocol_message object with proper operator<< and operator>>, you can receive and send such objects by directly manipulating the streambuf associated with a stream through stream::rdbuf(). A proper implementation of xsgetn would would directly call the networking primitive with the proper parameters, after sanity checking, taking into account the possibility of there being characters in the internal buffer, for complete correctness. We'll get a couple of branches for every call to recv(), so, yeah, we're probably not 100% on par with C here; but then, we'll only call recv() twice for each object received anyway. Also, an implementation of a networking streambuf can implement "no buffering" semantics set up by a streambuf.pubsetbuf(0, 0) call (like your typical fstream provides) to absolutely ensure there is no buffering going on. So you get operator semantics for free. :-) And perhaps even a putback area, if there's one provided by this particular streambuf implementation. I'll take a note of this use case, though. As soon as documentation is finished for my last proposal, I'll try and do some benchmarking. How large are your payloads, usually? -- Pedro Lamarão