2015-03-08 17 views
5

Ich habe eine serialisierte Struktur, die über Socket gesendet wird. Ich muss es Stück für Stück lesen, da eines seiner Felder die Größe der verbleibenden Daten enthält, also muss ich die ersten paar Bytes lesen, die Länge herausfinden und den Rest lesen. Das ist, was ich habe:boost :: asio lesen n Bytes von Socket zu 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; 

ich einen Blick auf

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

genommen haben, aber es kann nur Daten lesen boost :: asio :: Puffer. Ich frage mich, ob ich das gleiche mit boost :: asio :: streambuf machen könnte? Vielen Dank im Voraus.

Antwort

14

Es gibt Überlastungen sowohl für boost::asio::read() und boost::asio::async_read() die Instanzen boost::asio::basic_streambuf als Puffer akzeptieren:

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); 

Wenn eine Überlastung Aufruf, die keine CompletionCondition nicht akzeptiert, es ist das Äquivalent seiner zugehörigen Überlastung mit einem dem Aufruf CompletionCondition von boost::asio::transfer_all(), wodurch die Operation streambuf.max_size() Bytes gelesen hat.


für eine bekannte Menge an Bytes, die in eine streambuf Lesen, entweder Verwendung:

  • die boost::asio::transfer_exactly(n) CompletionCondition die Menge von Bytes aus der zusammengesetzten Operation übertragen zu begrenzen:

    std::size_t n = // ... 
    boost::asio::read(socket, streambuf, 
        boost::asio::transfer_exactly(n), error); 
    
  • Explizit eine Ausgabesequenz erstellen, die als Puffer dient, und dann die gelesenen Bytes in die Eingabesequenz des Streambufs schreiben:

    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); 
    

Hier ist ein komplettes Beispiel demonstrating diese beiden Ansätze:

#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. 
} 

Ausgang:

Writing: abc 
Read: abc 
Writing: def 
Read: def