http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/example/cpp03/http/client/sync_client.cpp
#include <iostream> #include <istream> #include <ostream> #include <string> #include <boost/asio.hpp> using boost::asio::ip::tcp; int main(int argc, char* argv[]) { try { if (argc != 3) { std::cout << "Usage: sync_client <server> <path>\n"; std::cout << "Example:\n"; std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n"; return 1; } boost::asio::io_service io_service; // Get a list of endpoints corresponding to the server name. tcp::resolver resolver(io_service); tcp::resolver::query query(argv[1], "http"); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); // Try each endpoint until we successfully establish a connection. tcp::socket socket(io_service); boost::asio::connect(socket, endpoint_iterator); // Form the request. We specify the "Connection: close" header so that the // server will close the socket after transmitting the response. This will // allow us to treat all data up until the EOF as the content. 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); // Read the response status line. The response streambuf will automatically // grow to accommodate the entire line(response). The growth may be limited by passing // a maximum size to the streambuf constructor. boost::asio::streambuf response; boost::asio::read_until(socket, response, "\r\n"); // Check that response is OK. std::istream response_stream(&response); std::string http_version; response_stream >> http_version; unsigned int status_code; response_stream >> status_code; std::string status_message; std::getline(response_stream, status_message); if (!response_stream || http_version.substr(0, 5) != "HTTP/") { std::cout << "Invalid response\n"; return 1; } if (status_code != 200) { std::cout << "Response returned with status code " << status_code << "\n"; return 1; } // Read the response headers, which are terminated by a blank line. boost::asio::read_until(socket, response, "\r\n\r\n"); // Process the response headers. std::string header; while (std::getline(response_stream, header) && header != "\r") std::cout << header << "\n"; std::cout << "\n"; // Write whatever content we already have to output. if (response.size() > 0) std::cout << &response; // Read until EOF, writing data to output as we go. boost::system::error_code error; while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) std::cout << &response; if (error != boost::asio::error::eof) throw boost::system::system_error(error); } catch (std::exception& e) { std::cout << "Exception: " << e.what() << "\n"; } return 0; }
streambuf继承自std::streambuf。就像std::streambuf本身,它不能拷贝构造。
当使用read_until时会有个难点:你需要记住你已经读取的字节数,因为下层的buffer可能多读取了一些字节(不像使用read()时)。比如:
std::cout << &buf << std::endl;
上述代码输出的字节可能比read_until读取到的多。
Attempt to read a certain amount of data from a stream before returning.
Read data into a streambuf until it contains a delimiter, matches a regular expression, or a function object indicates a match.
tcp::socket socket(io_service);
socket.open(tcp::v4());
boost::asio::socket_base::receive_buffer_size option;
socket.get_option(option);
boost::asio::socket_base::send_buffer_size option1;
socket.get_option(option1);
std::cout << "socket receive buf size: " << option.value() << "send buf size: " << option1.value() << std::endl;
输出: socket receive buf size: 43690,send buf size: 8192
boost socket的默认接收/输出缓冲大小是43690,8192
经测试发现:第一个read_until()已经从网络上把所有的响应都接收下来了。
测试手段:tcpdump 加 gdb, 在第一个read_until()处打断点,tcpdump的输出如下
14:35:34.859216 IP 172.30.18.222.44910 > 129.79.39.203.80: Flags [S], seq 850635159, win 14600, options [mss 1460,sackOK,TS val 1139674750 ecr 0,nop,wscale 6], length 0
E..<..@.@.*......O'..n.P2.........9..l.........
C..~........
14:35:35.043895 IP 129.79.39.203.80 > 172.30.18.222.44910: Flags [S.], seq 3643652864, ack 850635160, win 14480, options [mss 1460,sackOK,TS val 3905426011 ecr 1139674750,nop,wscale 7], length 0
E..<..@.'....O'......P.n.-..2.....8.9..........
...[C..~....
14:35:35.043941 IP 172.30.18.222.44910 > 129.79.39.203.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 1139674935 ecr 3905426011], length 0
E..4..@.@.*......O'..n.P2....-.......>.....
C..7...[
14:35:35.044514 IP 172.30.18.222.44910 > 129.79.39.203.80: Flags [P.], seq 1:87, ack 1, win 229, options [nop,nop,TS val 1139674936 ecr 3905426011], length 86
E.....@.@.*l.....O'..n.P2....-......h......
C..8...[GET /LICENSE_1_0.txt HTTP/1.0
Host: www.boost.org
Accept: */*
Connection: close
14:35:35.228615 IP 129.79.39.203.80 > 172.30.18.222.44910: Flags [.], ack 87, win 114, options [nop,nop,TS val 3905426196 ecr 1139674936], length 0
E..4..@.'.C..O'......P.n.-..2......r.......
....C..8
14:35:35.229999 IP 129.79.39.203.80 > 172.30.18.222.44910: Flags [.], seq 1:1449, ack 87, win 114, options [nop,nop,TS val 3905426196 ecr 1139674936], length 1448
E.....@.'.=..O'......P.n.-..2......r.......
....C..8HTTP/1.1 200 OK
Date: Tue, 12 Jan 2016 06:37:25 GMT
Server: Apache/2.2.15 (Red Hat)
Last-Modified: Sun, 15 Dec 2013 02:55:11 GMT
ETag: "2c53e9-53a-4ed89d2e171f1"
Accept-Ranges: bytes
Content-Length: 1338
Connection: close
Content-Type: text/plain
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABI
14:35:35.230013 IP 129.79.39.203.80 > 172.30.18.222.44910: Flags [FP.], seq 1449:1597, ack 87, win 114, options [nop,nop,TS val 3905426196 ecr 1139674936], length 148
E.....@.'.C..O'......P.n.-..2......r.......
....C..8LITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
14:35:35.230420 IP 172.30.18.222.44910 > 129.79.39.203.80: Flags [.], ack 1449, win 274, options [nop,nop,TS val 1139675122 ecr 3905426196], length 0
E..4..@.@.*......O'..n.P2....-.............
C.......
14:35:35.230784 IP 172.30.18.222.44910 > 129.79.39.203.80: Flags [R.], seq 87, ack 1598, win 319, options [nop,nop,TS val 1139675122 ecr 3905426196], length 0
E..4..@.@.*......O'..n.P2....-.>...?.......
C.......
可见一次read_until()已经从网络上读完了所有的响应。我的理解是:把从网络上读来的东西全部缓存在socket的buffer中。
经测试发现:
在刚开始声明response时,其buffer大小是128,
(gdb) p response
$3 = {
<std::basic_streambuf<char, std::char_traits<char> >> = {<No data fields>},
<boost::asio::detail::noncopyable> = {<No data fields>},
members of boost::asio::basic_streambuf<std::allocator<char> >:
max_size_ = 500,
buffer_ = std::vector of length 128, capacity 128 = {0 '\000',。。。}
当response被用来read_until后,其buffer大小默认是512,如下
(gdb) p response
$2 = {
<std::basic_streambuf<char, std::char_traits<char> >> = {<No data fields>},
<boost::asio::detail::noncopyable> = {<No data fields>},
members of boost::asio::basic_streambuf<std::allocator<char> >:
max_size_ = 18446744073709551615,
buffer_ = std::vector of length 512, capacity 512 = {72 'H', 。。。。}
(gdb) p response.size()
$3 = 512
每次从response中读出内容时,response.size()都会减少
读完所有的http头后,把response中剩余的内容输出
// Write whatever content we already have to output.
if (response.size() > 0)
std::cout << &response;
此时,
(gdb) p response.size()
$3 = 0
紧接着继续从socket的buffer中把数据读到response中
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error)) //response.size() == 512
std::cout << &response; //response.size() == 0
cout << &response 同样也会消耗response缓冲。
不知道理解的对不对。。。。。。
浙公网安备 33010602011771号