Ich habe Probleme mit streambuf Management in Asio. Ich benutze Boost 1.58 auf Ubuntu. Als erstes ist hier der Code:boost :: asio :: streambuf abrufen xml Daten obwohl https
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/completion_condition.hpp>
class example
{
private:
// asio components
boost::asio::io_service service;
boost::asio::ssl::context context;
boost::asio::ip::tcp::resolver::query query;
boost::asio::ip::tcp::resolver resolver;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket;
boost::asio::streambuf requestBuf, responseBuf;
// callbacks
void handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if (!err)
{
boost::asio::async_connect(socket.lowest_layer(), endpoint_iterator,
boost::bind(&example::handle_connect, this,
boost::asio::placeholders::error));
}
}
void handle_connect(const boost::system::error_code& err)
{
if (!err)
{
socket.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&example::handle_handshake, this,
boost::asio::placeholders::error));
}
}
void handle_handshake(const boost::system::error_code& err)
{
if (!err)
{
boost::asio::async_write(socket, requestBuf,
boost::bind(&example::handle_write_request, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
void handle_write_request(const boost::system::error_code& err, size_t bytes_transferred)
{
if (!err)
{
boost::asio::async_read(socket, responseBuf,
boost::asio::transfer_at_least(1),
boost::bind(&example::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
void handle_read(const boost::system::error_code& err,
size_t bytes_transferred)
{
if (!err)
{
boost::asio::async_read(socket, responseBuf,
boost::asio::transfer_at_least(1),
boost::bind(&example::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
public:
example() : context(boost::asio::ssl::context::sslv23),
resolver(service),
socket(service, context),
query("www.quandl.com", "443") {}
void work()
{
// set security
context.set_default_verify_paths();
socket.set_verify_mode(boost::asio::ssl::verify_peer);
// in case this no longer works, generate a new key from https://www.quandl.com/
std::string api_key = "4jufXHL8S4XxyM6gzbA_";
// build the query
std::stringstream ss;
ss << "api/v3/datasets/";
ss << "RBA" << "/" << "FXRUKPS" << ".";
ss << "xml" << "?sort_order=asc";
ss << "?api_key=" << api_key;
ss << "&start_date=" << "2000-01-01";
ss << "&end_date=" << "2003-01-01";
std::ostream request_stream(&requestBuf);
request_stream << "GET /";
request_stream << ss.str();
request_stream << " HTTP/1.1\r\n";
request_stream << "Host: " << "www.quandl.com" << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
resolver.async_resolve(query,
boost::bind(&example::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
service.run();
std::cout << &responseBuf;
}
};
int main(int argc, char * argv[])
{
// this is a test
int retVal; try
{
example f; f.work();
retVal = 0;
}
catch (std::exception & ex)
{
std::cout << "an error occured:" << ex.what() << std::endl;
retVal = 1;
}
return retVal;
}
Hier ist mein Problem: Das Beispiel funktioniert einwandfrei, wenn die resultierenden Daten nicht zu lang sind (ein paar tausend Zeichen). Sobald async_read jedoch eine ungerade Anzahl von Zeichen zurückgibt (standardmäßig ist bytes_transfer 512 Zeichen), wird der Streambuf beschädigt und der nächste async_read-Aufruf enthält einige zusätzliche Zeichen.
Ich habe erfolglos viele Variationen des obigen Codes ausprobiert: mit transfer_exactly(), streambuf.consume() aufrufen, um den Puffer zu löschen, einen weiteren Puffer passieren, sobald ich eine ungerade Anzahl von zurückgegebenen Zeichen, etc. Keine von diesen feststellen Lösungen funktionierten.
Was fehlt mir hier? Thx
Ihr Code funktioniert für mich. Mein Verdacht ist, dass Sie mit [chunked transfer encoding] (https://en.wikipedia.org/wiki/Chunked_transfer_encoding) nicht vertraut sind und diese "paar zusätzlichen Zeichen" in Ihrem Stream sind eigentlich die Chunk-Header. – rhashimoto
Hallo, definitiv, ich habe diesen Punkt vermisst. Dank Ihrer Bemerkung habe ich begonnen, meinen Code zu ändern, um die Chunck-Trennzeichen zu verfolgen, aber dann habe ich gemerkt, dass Asio-Nachrichten nicht mit den Server-Chuncks in Verbindung stehen (die Trennzeichen könnten sich in der Mitte des Puffers befinden). Also habe ich meine Strategie geändert, zuerst die gesamte Nachricht in den Puffer geladen und dann den Streamstring von dort aufgefüllt. –