
On Mon, 13 Jun 2005 15:13:19 +0400, <pedro.lamarao@mndfck.org> wrote:
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().
[...]
So you get operator semantics for free. :-) And perhaps even a putback area, if there's one provided by this particular streambuf implementation.
Sounds interesting, but I don't see how this can work well with nonblocking sockets. You have to store how much bytes have already been read/sent somewhere.
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?
~8k. -- Maxim Yegorushkin