[asio] new version, prototype iostreams support

Hello all, asio version 0.3.7 has been released. It may be downloaded from the asio sourceforge page at http://asio.sourceforge.net. This release corresponds to what is currently checked into Boost CVS. A list of the main changes in this version since 0.3.6 is available at: <http://sourceforge.net/project/shownotes.php?group_id=122478&release_id=426239> As previously discussed, in this version I have included some prototype iostreams and streambuf support. Feedback on this would be appreciated. An example use of the iostreams classes in a client program can be seen here: <http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/examples/iostreams_daytime_client_cpp.html> The iostreams classes may also be used in simple servers, as illustrated here: <http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/examples/iostreams_daytime_server_cpp.html> To better support line-based (or other delimiter-based) protocols, a new asio::streambuf class, read_until() and async_read_until() functions have been added. An example showing these in a synchronous use case (an HTTP 1.0 client) can be seen here: <http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/examples/httpclient_sync_client_cpp.html> And the asynchronous equivalent is available at: <http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/examples/httpclient_async_client_cpp.html> Cheers, Chris

Christopher Kohlhoff wrote:
Hello all,
asio version 0.3.7 has been released. It may be downloaded from the asio sourceforge page at http://asio.sourceforge.net. This release corresponds to what is currently checked into Boost CVS.
A list of the main changes in this version since 0.3.6 is available at:
<http://sourceforge.net/project/shownotes.php?group_id=122478&release_id=426239>
Wow, a lot of changes. There is one thing that caught my eye. In the changelog you have the following comment:
* Resolver replaces ipv4::host_resolver.
...
ip::tcp::resolver resolver(io_service);
Why is "resolver" in the "ip::tcp" namespace? A DNS resolver certainly has nothing to do with the TCP protocol. It should be in the "ip" namespace instead. Cheers, Peter

Peter Petrov escreveu:
Wow, a lot of changes.
There is one thing that caught my eye. In the changelog you have the following comment:
* Resolver replaces ipv4::host_resolver.
...
ip::tcp::resolver resolver(io_service);
Why is "resolver" in the "ip::tcp" namespace? A DNS resolver certainly has nothing to do with the TCP protocol. It should be in the "ip" namespace instead.
It shouldn't be in the "ip" namespace either. The name translation service in any modern operating system can return address objects for any network families it supports. In practice, getaddrinfo can return addresses for IPv4 and IPv6. There is no reason why it can't return addresses for any other kind of network (unless naming objects in that network is radically different from "host"/"service"). -- Pedro Lamarão

Pedro Lamarão wrote:
Peter Petrov escreveu:
Wow, a lot of changes.
There is one thing that caught my eye. In the changelog you have the following comment:
* Resolver replaces ipv4::host_resolver.
...
ip::tcp::resolver resolver(io_service); Why is "resolver" in the "ip::tcp" namespace? A DNS resolver certainly has nothing to do with the TCP protocol. It should be in the "ip" namespace instead.
It shouldn't be in the "ip" namespace either.
The name translation service in any modern operating system can return address objects for any network families it supports.
In practice, getaddrinfo can return addresses for IPv4 and IPv6. There is no reason why it can't return addresses for any other kind of network (unless naming objects in that network is radically different from "host"/"service").
Just because the system resolver (getaddrinfo) could in principle resolve all kind of addresses, it doesn't mean that the asio resolver should. The asio resolver returns a protocol specific address (actually an iterator to a list of protocol specific addresses) and thus is strongly typed. If the resolver where to be generic, it would return an iterator to an heterogeneous list of addresses: the address (and socket types initialized from the address) would need to be dynamically typed. The asio interface is designed with static (not dynamic) polymorphisms in mind, so the resolver should be protocol specific. Note that a tcp address is also an tcp6, ip and ip6 address (v4 and v6 polymorphism is built in the protocol), so it should rightly belong in the 'ip' namespace. Ciao, -- Giovanni P. Deretta

Giovanni P. Deretta <gpderetta@gmail.com> wrote:
Pedro Lamarão wrote:
Peter Petrov escreveu:
Why is "resolver" in the "ip::tcp" namespace? A DNS resolver certainly has nothing to do with the TCP protocol. It should be in the "ip" namespace instead.
It shouldn't be in the "ip" namespace either.
The name translation service in any modern operating system can return address objects for any network families it supports.
In practice, getaddrinfo can return addresses for IPv4 and IPv6. There is no reason why it can't return addresses for any other kind of network (unless naming objects in that network is radically different from "host"/"service").
Just because the system resolver (getaddrinfo) could in principle resolve all kind of addresses, it doesn't mean that the asio resolver should.
The asio resolver returns a protocol specific address (actually an iterator to a list of protocol specific addresses) and thus is strongly typed. If the resolver where to be generic, it would return an iterator to an heterogeneous list of addresses: the address (and socket types initialized from the address) would need to be dynamically typed. The asio interface is designed with static (not dynamic) polymorphisms in mind, so the resolver should be protocol specific.
What Giovanni said. After all, it was his suggestion in the review to add this strong typing :) I do feel that the new asio interface strikes the right balance between strong typing (to allow the compiler to detect more errors) and dynamic typing (in that you can use ip::tcp::socket without needing to know if it's IPv4 or IPv6). Note that it is possible to implement a generic socket using asio. You would have to create a runtime-polymorphic protocol class, and then instantiate the basic_*_socket<> and basic_resolver<> templates on it. Cheers, Chris

Hi Peter, Peter Petrov <ppetrov@ppetrov.com> wrote:
There is one thing that caught my eye. In the changelog you have the following comment:
* Resolver replaces ipv4::host_resolver.
...
ip::tcp::resolver resolver(io_service);
Why is "resolver" in the "ip::tcp" namespace? A DNS resolver certainly has nothing to do with the TCP protocol. It should be in the "ip" namespace instead.
Unlike the old host_resolver class, which would resolve a host name into an address, the new resolvers turn host name and service name into a list of endpoints. This interface is based on getaddrinfo() function. We now have: - ip::tcp::resolver, which returns a list of ip::tcp::endpoint objects - ip::udp::resolver, which returns a list of ip::udp::endpoint objects Resolvers for other protocols, can (if supported by getaddrinfo on the target platform) be created by instantiating the asio::basic_resolver<> template on an appropriately defined protocol class. So, ip::tcp::resolver is very much specific to TCP, but basic_resolver<> isn't - it's not even specific to IP (in theory, anyway). Cheers, Chris

On 6/25/06, Christopher Kohlhoff <chris@kohlhoff.com> wrote:
Hi Peter,
Peter Petrov <ppetrov@ppetrov.com> wrote:
There is one thing that caught my eye. In the changelog you have the following comment:
* Resolver replaces ipv4::host_resolver.
...
ip::tcp::resolver resolver(io_service);
Why is "resolver" in the "ip::tcp" namespace? A DNS resolver certainly has nothing to do with the TCP protocol. It should be in the "ip" namespace instead.
Unlike the old host_resolver class, which would resolve a host name into an address, the new resolvers turn host name and service name into a list of endpoints. This interface is based on getaddrinfo() function.
We now have:
- ip::tcp::resolver, which returns a list of ip::tcp::endpoint objects
- ip::udp::resolver, which returns a list of ip::udp::endpoint objects
Resolvers for other protocols, can (if supported by getaddrinfo on the target platform) be created by instantiating the asio::basic_resolver<> template on an appropriately defined protocol class.
So, ip::tcp::resolver is very much specific to TCP, but basic_resolver<> isn't - it's not even specific to IP (in theory, anyway).
I'd still love to see a utility function connect_host which resolves creates a socket and connects. considering nearly every app will end up rewriting the wheel so to speek with that.
Cheers, Chris
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Cory Nelson http://www.int64.org

Hi Cory, Cory Nelson <phrosty@gmail.com> wrote:
I'd still love to see a utility function connect_host which resolves creates a socket and connects. considering nearly every app will end up rewriting the wheel so to speek with that.
Yes, I've often thought about adding something like this. The biggest issue that has stopped me from doing it yet is the question of how to implement cancellation of an asynchronous version. I.e. during host/service resolution it would require cancellation of the resolver, but cancelling the connect needs the socket to be closed. Another thing that has kept me from doing it is the thought that perhaps most non-trivial apps wouldn't use it anyway. For example, when I run 'telnet localhost' on my system, I get: Trying ::1... telnet: connect to address ::1: Connection refused Trying 127.0.0.1... telnet: connect to address 127.0.0.1: Connection refused telnet: Unable to connect to remote host I would suspect it is a reasonably common requirement that an application display the addresses that it is trying as it tries them, if not to the user at least to an event log. The bottom line is that I'd be very happy to include such a function in asio, but unless we can come up with an elegant interface for it asap, I'm probably not going to be able to include it in a TR2 proposal. Cheers, Chris

On 6/21/06, Christopher Kohlhoff <chris@kohlhoff.com> wrote:
As previously discussed, in this version I have included some prototype iostreams and streambuf support. Feedback on this would be appreciated.
This is fantastic, Chris. I think that anyone writing simple stream-based network clients and servers will find these new interfaces very intuitive. tcp::iostream s(argv[1], "daytime"); std::string line; std::getline(s, line); std::cout << line << std::endl; It really can't get much easier than that. Kudos. -- Caleb Epstein

On 6/21/06, Christopher Kohlhoff <chris@kohlhoff.com> wrote:
Hello all,
asio version 0.3.7 has been released. It may be downloaded from the asio sourceforge page at http://asio.sourceforge.net. This release corresponds to what is currently checked into Boost CVS.
A list of the main changes in this version since 0.3.6 is available at:
< http://sourceforge.net/project/shownotes.php?group_id=122478&release_id=426239
As previously discussed, in this version I have included some prototype iostreams and streambuf support. Feedback on this would be appreciated.
Excellent work! I've been expectantly awaiting this release to integrate into our own select-based communication layer as a more-robust replacement. Feedback will be upcoming after I get back from vacation. -a

On 6/21/06, Christopher Kohlhoff <chris@kohlhoff.com> wrote:
Hello all,
As previously discussed, in this version I have included some prototype iostreams and streambuf support. Feedback on this would be appreciated.
From http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/examples/httpclie... :
boost::asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET " << argv[2] << " HTTP/1.0\r\n"; request_stream << "Host: " << argv[1] << "\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Connection: close\r\n\r\n"; // Send the request. boost::asio::write(socket, request); What advantage is the boost::asio::streambuf providing here? I don't see a different between it and just using a stringstream and sending the .str().
An example use of the iostreams classes in a client program can be seen here:
Very nice. Just took a quick peek, ~ Scott McMurray

Hi Scott, me22 <me22.ca@gmail.com> wrote:
From http://asio.sourceforge.net/boost_asio_0_3_7/libs/ asio/doc/examples/httpclient_sync_client_cpp.html :
boost::asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET " << argv[2] << " HTTP/1.0\r\n"; request_stream << "Host: " << argv[1] << "\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Connection: close\r\n\r\n";
// Send the request. boost::asio::write(socket, request);
What advantage is the boost::asio::streambuf providing here? I don't see a different between it and just using a stringstream and sending the .str().
For writing data, the main advantage over stringstream (or strstream) that I see is that data copying can be minimised. I've tried to keep the interface such that internal buffers can be allocated separately and chained deque-style. Using a chain of buffers, data can be appended to the end or extracted from the front without needing to copy around the existing contents. However, if there's a single contiguous buffer then every time the buffer is resized there's the possibility that all data in the buffer would have to be copied to a new location. Note that the current implementation of asio::streambuf does use a contiguous buffer so I could implement it quickly :) So at the moment this particular benefit isn't realised. I don't know whether the standard permits a stringstream using non-contiguous buffers. 27.7.1.3/8 at least seems to promote using a single character array. However, even if it is permitted... Depending on your std::string and std::stringstream implementation, you will probably incur an additional memory allocation and data copy when you call .str() on the stringstream to extract the contents. Calling asio::write() on an asio::streambuf is guaranteed to write directly from the internal buffers. Cheers, Chris
participants (8)
-
Andrew Finkenstadt
-
Caleb Epstein
-
Christopher Kohlhoff
-
Cory Nelson
-
Giovanni P. Deretta
-
me22
-
Pedro Lamarão
-
Peter Petrov