boost::asio::streambufは、自動的にサイズ変更可能なバッファクラスです。このバッファタイプは、データの内容を前提とした読み取り操作を開始するときによく使用されます。データのサイズは必ずしも必要ではありません。例えば、どれくらいのデータを読み込むかを知らずに、改行まではboost::asio::read_until()
を読むことができます。
本文の長さを含む固定サイズのヘッダーとヘッダーの後に可変長ボディーがあるアプリケーションプロトコルの場合は、std::vector<>
などのバッファータイプの使用を検討してください。簿記の一部を簡素化しながら、これは、boost::asio::streambuf
と柔軟性の同じレベルを提供します:
std::vector<char> buffer;
// Read header.
buffer.resize(protocol::header_size);
boost::asio::read(socket, boost::asio::buffer(buffer));
// Extract body size from header, resize buffer, then read
// body.
auto body_size = parse_header(buffer);
buffer.resize(body_size);
boost::asio::read(socket, boost::asio::buffer(buffer));
process_body(buffer);
方法vector
のサイズを変更しない読み取り操作で読み取られるデータの量を示しています。 streambuf
を使用する場合、人はこれらの動作を直接入力および出力シーケンスを管理しなければならない:ここ
boost::asio::streambuf streambuf;
// Read header into the streambuf's output sequence.
auto bytes_transferred = boost::asio::read(socket,
streambuf.prepare(protocol::header_size));
// Commit read data from output sequence into the input
// sequence.
streambuf.commit(bytes_transferred);
// Extract body size from header. This would likely
// consume all of the streambuf's input sequence.
auto body_size = parse_header(streambuf);
// Clear the input sequence.
streambuf.consume(streambuf.size());
// Ready body into the streambuf's output sequence.
bytes_transferred = boost::asio::read(socket,
streambuf.prepare(body_size));
// Commit read data from output sequence into the input
// sequence.
streambuf.commit(bytes_transferred);
// Extract all of stream into the body.
process_body(streambuf);
このアプローチ完全な例demonstratingある:
#include <array> // std::array
#include <functional> // std::bind
#include <iostream> // std::cout, std::endl
#include <vector> // std::vector
#include <boost/asio.hpp>
// This example is not interested in the handlers, so provide a noop function
// that will be passed to bind to meet the handler concept requirements.
void noop() {}
// The application protocol will consists of a fixed-size header
// containing a std::size_t with the length of the following
// variable length body. To keep it simple, some details
// are ommitted, such as endian handling.
namespace protocol {
enum
{
header_size = sizeof(std::size_t)
};
} // namespace protocol
std::vector<char> build_header(const std::string& body)
{
std::vector<char> buffer(protocol::header_size);
auto body_size = body.size();
std::memcpy(&buffer[0], &body_size, sizeof body_size);
return buffer;
}
std::size_t parse_header(const std::vector<char>& buffer)
{
return *reinterpret_cast<const std::size_t*>(&buffer[0]);
}
int main()
{
using boost::asio::ip::tcp;
// Create all I/O objects.
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0));
tcp::socket socket1(io_service);
tcp::socket socket2(io_service);
// Connect the sockets.
acceptor.async_accept(socket1, std::bind(&noop));
socket2.async_connect(acceptor.local_endpoint(), std::bind(&noop));
io_service.run();
io_service.reset();
// Write a message from socket1 to socket2.
std::string test_message = "this is a test message";
{
auto header = build_header(test_message);
// Gather header and body into a single buffer.
std::array<boost::asio::const_buffer, 2> buffers = {{
boost::asio::buffer(header),
boost::asio::buffer(test_message)
}};
// Write header and body to socket.
boost::asio::write(socket1, buffers);
}
// Read from socket2.
{
// Use a vector to allow for re-sizing based on the
// amount of data needing to be read. This also reduces
// on the amount of reallocations if the vector is reused.
std::vector<char> buffer;
// Read header.
buffer.resize(protocol::header_size);
boost::asio::read(socket2, boost::asio::buffer(buffer));
// Extract body size from header, resize buffer, then read
// body.
auto body_size = parse_header(buffer);
buffer.resize(body_size);
boost::asio::read(socket2, boost::asio::buffer(buffer));
// Verify body was read.
assert(std::equal(begin(buffer), end(buffer),
begin(test_message)));
std::cout << "received: \n"
" header: " << body_size << "\n"
" body: ";
std::cout.write(&buffer[0], buffer.size());
std::cout << std::endl;
}
}
は出力:
received:
header: 22
body: this is a test message
どのような行でsegfaultsを知っていますか? – Tobias
申し訳ありませんが、streambufと関係があります。 – Shuzheng
まず、何桁のオクテット/バイトを記入するかを知っていれば、通常の固定サイズのバッファを使用していないのはなぜですか?第二に、私は 'boost :: asio :: async_read_until'や' boost :: asio :: async_read_some'を使うと、元の問題に関してより意味をなさないと思います。 – Tobias