| [/ |
| / Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
| / |
| / Distributed under the Boost Software License, Version 1.0. (See accompanying |
| / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| /] |
| |
| [section:line_based Line-Based Operations] |
| |
| Many commonly-used internet protocols are line-based, which means that they |
| have protocol elements that are delimited by the character sequence `"\r\n"`. |
| Examples include HTTP, SMTP and FTP. To more easily permit the implementation |
| of line-based protocols, as well as other protocols that use delimiters, Asio |
| includes the functions `read_until()` and `async_read_until()`. |
| |
| The following example illustrates the use of `async_read_until()` in an HTTP |
| server, to receive the first line of an HTTP request from a client: |
| |
| class http_connection |
| { |
| ... |
| |
| void start() |
| { |
| asio::async_read_until(socket_, data_, "\r\n", |
| boost::bind(&http_connection::handle_request_line, this, _1)); |
| } |
| |
| void handle_request_line(asio::error_code ec) |
| { |
| if (!ec) |
| { |
| std::string method, uri, version; |
| char sp1, sp2, cr, lf; |
| std::istream is(&data_); |
| is.unsetf(std::ios_base::skipws); |
| is >> method >> sp1 >> uri >> sp2 >> version >> cr >> lf; |
| ... |
| } |
| } |
| |
| ... |
| |
| asio::ip::tcp::socket socket_; |
| asio::streambuf data_; |
| }; |
| |
| The `streambuf` data member serves as a place to store the data that has been |
| read from the socket before it is searched for the delimiter. It is important |
| to remember that there may be additional data ['after] the delimiter. This |
| surplus data should be left in the `streambuf` so that it may be inspected by a |
| subsequent call to `read_until()` or `async_read_until()`. |
| |
| The delimiters may be specified as a single `char`, a `std::string` or a |
| `boost::regex`. The `read_until()` and `async_read_until()` functions also |
| include overloads that accept a user-defined function object called a match |
| condition. For example, to read data into a streambuf until whitespace is |
| encountered: |
| |
| typedef asio::buffers_iterator< |
| asio::streambuf::const_buffers_type> iterator; |
| |
| std::pair<iterator, bool> |
| match_whitespace(iterator begin, iterator end) |
| { |
| iterator i = begin; |
| while (i != end) |
| if (std::isspace(*i++)) |
| return std::make_pair(i, true); |
| return std::make_pair(i, false); |
| } |
| ... |
| asio::streambuf b; |
| asio::read_until(s, b, match_whitespace); |
| |
| To read data into a streambuf until a matching character is found: |
| |
| class match_char |
| { |
| public: |
| explicit match_char(char c) : c_(c) {} |
| |
| template <typename Iterator> |
| std::pair<Iterator, bool> operator()( |
| Iterator begin, Iterator end) const |
| { |
| Iterator i = begin; |
| while (i != end) |
| if (c_ == *i++) |
| return std::make_pair(i, true); |
| return std::make_pair(i, false); |
| } |
| |
| private: |
| char c_; |
| }; |
| |
| namespace asio { |
| template <> struct is_match_condition<match_char> |
| : public boost::true_type {}; |
| } // namespace asio |
| ... |
| asio::streambuf b; |
| asio::read_until(s, b, match_char('a')); |
| |
| The `is_match_condition<>` type trait automatically evaluates to true for |
| functions, and for function objects with a nested `result_type` typedef. For |
| other types the trait must be explicitly specialised, as shown above. |
| |
| [heading See Also] |
| |
| [link asio.reference.async_read_until async_read_until()], |
| [link asio.reference.is_match_condition is_match_condition], |
| [link asio.reference.read_until read_until()], |
| [link asio.reference.streambuf streambuf], |
| [link asio.examples.cpp03_examples.http_client HTTP client example]. |
| |
| [endsect] |