Monday, January 15, 2007

Unbuffered socket iostreams

Boost.Asio includes an iostreams-based interface to TCP sockets, ip::tcp::iostream, for simple use cases. However, like the file iostreams provided by the standard library, ip::tcp::iostream buffers input and output data. This can lead to problems if you forget to explicitly flush the stream. For example, consider the following code to perform an HTTP request:
ip::tcp::iostream stream("", "http");
stream << "GET / HTTP/1.0\r\n"
<< "Host:\r\n"
<< "\r\n";

std::string response_line;
std::getline(stream, response_line);
The code will be stuck on the getline() call waiting for the response, because the request will still be sitting stream's output buffer. The correct code looks like this:
ip::tcp::iostream stream("", "http");
stream << "GET / HTTP/1.0\r\n"
<< "Host:\r\n"
<< "\r\n"
<< std::flush;
The std::flush will cause the stream to send the entire contents of its output buffer at that point.

Boost.Asio now supports an alternative solution: turn off the stream's output buffering. This is accomplished as follows:
ip::tcp::iostream stream("", "http");
stream.rdbuf()->pubsetbuf(0, 0);
stream << "GET / HTTP/1.0\r\n"
<< "Host:\r\n"
<< "\r\n";
Now you can send and receive to your heart's content, without having to worry about whether your message is stuck in the output buffer, but be warned: an unbuffered stream is a lot less efficient in terms of system calls. Don't use this feature if you care about performance.


Anonymous said...

Is it not possible to tie it to itself (or something similar) so that it automagically flushes on a read operation?

chris said...

Interesting idea, I didn't think of that. Using tie() is not exactly the same as an unbuffered stream, but it does give the expected behaviour for request-response style protocols (like HTTP, SMTP etc). Perhaps it should also be set by default, hmmm... something to think about.

Jeremy Fincher said...

Just a note to say that I had the same thought that anonymous did, and think it's an entirely reasonable default for the stream to flush its write buffer when a read is attempted. In fact, I was surprised that it didn't :)

chris said...

In fact, I did think about it and decided it should be on by default. Consequently my revised TR2 proposal (N2175) does specify that the stream should be tied to itself.

However, it seems I forgot to actually implement it! :-/

Anonymous said...

Now, it would be nice if we could do async reads from socket iostreams. The example is nice, but it only covers one-off sends and receives. As far as I can tell, there is no way to get the iostream ease of use for reading from or writing to a socket unless you do it completely synchronously, since the underlying basic_socket_streambuf doesn't support anything but an asynchronous connect().

Such functionality would also simplify one form of async_read(), it seems a bit strange that the first argument is something like an ip::tcp::socket and the second argument is a basic_stream_buf, which is itself a basic_socket.

thomas said...

It is truly a nice and useful piece of info. I am glad that you simply shared this useful information with us. Please keep us informed like this. Thank you for sharing.

GOSTOPSITE33 said...

I discovered your site internet site on yahoo and check a few of your early posts. Continue to keep inside the excellent operate. I just additional encourage RSS feed to my MSN News Reader. Seeking forward to reading far more on your part later on!…


I do believe all of the concepts you have introduced in your post. They’re very convincing and will definitely work. Nonetheless, the posts are very quick for newbies. May just you please extend them a bit from next time? Thank you for the post.

GUIDE1903 said...

Hi, I think that I saw you visited my web site so I came to “return the favor". I am trying to find things to enhance my web site! I suppose its ok to use some of your ideas!!

TOTOSAFEDB33 said...

I can’t imagine focusing long enough to research; much less write this kind of article. You’ve outdone yourself with this material. This is great content.

CasinoMecca said...