Asio에서 streambuf 관리에 어려움을 겪고 있습니다. 우분투에서 1.58을 사용하고 있습니다. 첫째, 여기에 코드입니다 :boost :: asio :: streambuf https를 통해 xml 데이터 검색
#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;
}
여기 내 문제가 : 결과 데이터가 (몇 수천 문자) 너무 오래하지 않은 경우의 예는 완벽하게 작동합니다. 그러나 async_read가 고르지 않은 문자 (기본 bytes_transferred는 512 문자)를 반환하면 곧바로 streambuf가 손상되고 다음 async_read 호출에 몇 가지 추가 문자가 포함됩니다.
transfer_exactly()를 사용하여 bufferbuf.consume()을 호출하여 버퍼를 지우고, 고르지 않은 수의 문자가 반환되는 즉시 다른 버퍼를 전달하는 등 많은 변형을 시도해 보았습니다. 솔루션이 작동했습니다.
무엇이 여기에 있습니까? THX
주석 교환 결정된
코드가 작동합니다. 제 생각에 당신은 [chunked transfer encoding] (https://en.wikipedia.org/wiki/Chunked_transfer_encoding)에 익숙하지 않고 스트림에있는 "몇 개의 추가 문자"는 실제로 청크 헤더입니다. – rhashimoto
안녕하세요, 저는 분명히이 지점을 놓치고있었습니다. 귀하의 발언 덕분에 나는 chunck 구분 기호를 추적하기 위해 코드를 변경하기 시작했지만 asio 메시지는 서버 chunck와 관련이 없다는 것을 알았습니다 (구분 기호는 버퍼 중간에있을 수 있음). 그래서 전략을 바꿨습니다. 처음에는 전체 메시지를 버퍼에로드하고 거기에서 스트림 스트링을 채웠습니다. –