2015-03-08 2 views
5

У меня есть сериализованная структура, которая отправляется через сокет. Мне нужно прочитать его кусками, так как одно из его полей содержит размер оставшихся данных, поэтому мне нужно прочитать первые несколько байтов, узнать длину и прочитать остальные. Это то, что я получил:boost :: asio read n bytes from socket to streambuf

boost::asio::streambuf buffer; 
    boost::system::error_code err_code; 
    // here I need to read only first 16 bytes 
    boost::asio::read(socket, buffer, err_code); 
    std::istream is(&buffer); 
    boost::archive::binary_iarchive ia(is); 
    ia >> my_struct; 

Я принял взглянуть на

boost::asio::async_read(s, boost::asio::buffer(data, size), handler); 

, но он может только читать данные, чтобы повысить :: ASIO :: буфер. Мне интересно, могу ли я сделать то же самое с boost :: asio :: streambuf? Заранее спасибо.

ответ

14

Есть перегрузками для обоих boost::asio::read() и boost::asio::async_read(), которые принимают экземпляры boost::asio::basic_streambuf в качестве буфера:

read(SyncReadStream&, basic_streambuf&); 
read(SyncReadStream&, basic_streambuf&, CompletionCondition); 

read(SyncReadStream&, basic_streambuf&, boost::system::error_code&); 
read(SyncReadStream&, basic_streambuf&, CompletionCondition, 
    boost::system::error_code&); 

async_read(AsyncReadStream&, basic_streambuf&, ReadHandler); 
async_read(AsyncReadStream&, basic_streambuf&, CompletionCondition, 
      ReadHandler); 

При вызове перегрузки, которая не принимает CompletionCondition, это эквивалентно вызову связанной с ним перегрузки с CompletionCondition boost::asio::transfer_all(), заставляя операцию читать streambuf.max_size() байт.


Для чтения известного количества байт в streambuf, либо использовать:

  • boost::asio::transfer_exactly(n) CompletionCondition, чтобы ограничить количество байт, переданных из составленных операций:

    std::size_t n = // ... 
    boost::asio::read(socket, streambuf, 
        boost::asio::transfer_exactly(n), error); 
    
  • Явно создаю последовательность вывода, которая будет служить в качестве буфера, а затем отправляет байты, считанные в входную последовательность streambuf:

    std::size_t n = // ... 
    std::size_t bytes_transferred = boost::asio::read(socket, 
        streambuf.prepare(n), // creates a boost::asio::buffer 
        error); 
    streambuf.commit(bytes_transferred); 
    

Вот полный пример demonstrating оба этих подхода:

#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.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() {} 

std::string make_string(boost::asio::streambuf& streambuf) 
{ 
    return {boost::asio::buffers_begin(streambuf.data()), 
      boost::asio::buffers_end(streambuf.data())}; 
} 

int main() 
{ 
    using boost::asio::ip::tcp; 
    boost::asio::io_service io_service; 

    // Create all I/O objects. 
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0)); 
    tcp::socket server_socket(io_service); 
    tcp::socket client_socket(io_service); 

    // Connect client and server sockets. 
    acceptor.async_accept(server_socket, boost::bind(&noop)); 
    client_socket.async_connect(acceptor.local_endpoint(), boost::bind(&noop)); 
    io_service.run(); 

    // Write to server. 
    boost::asio::streambuf write_buffer; 
    std::ostream output(&write_buffer); 
    output << "abc"; 
    std::cout << "Writing: " << make_string(write_buffer) << std::endl; 
    auto bytes_transferred = boost::asio::write(server_socket, write_buffer); 

    // Read from client. 
    boost::asio::streambuf read_buffer; 
    bytes_transferred = boost::asio::read(client_socket, read_buffer, 
     boost::asio::transfer_exactly(bytes_transferred)); 
    std::cout << "Read: " << make_string(read_buffer) << std::endl; 
    read_buffer.consume(bytes_transferred); // Remove data that was read. 

    // Write to server. 
    output << "def"; 
    std::cout << "Writing: " << make_string(write_buffer) << std::endl; 
    bytes_transferred = boost::asio::write(server_socket, write_buffer); 

    // Read from client. 
    bytes_transferred = boost::asio::read(client_socket, 
     read_buffer.prepare(bytes_transferred)); 
    read_buffer.commit(bytes_transferred);  
    std::cout << "Read: " << make_string(read_buffer) << std::endl; 
    read_buffer.consume(bytes_transferred); // Remove data that was read. 
} 

Выход:

Writing: abc 
Read: abc 
Writing: def 
Read: def 
Смежные вопросы