Ответ на запрос клиента HTTP с переполнением стека в pion-net

Я хочу создать простой HTTPClient с пион-сеть (Пион-нетто рычаги увеличить :: Asio.).
Загрузочная версия 1.49
Пион-сеть Версия 4.11

Мой клиент должен просто уметь:

  • отправить запрос HTTP (это работает)
  • получить ответ HTTP (не работает)
  • асинхронный код не является обязательным, синхронный будет в порядке

Вот что я получил:

#include <iostream>
#include "boost/asio.hpp"#include "boost/thread.hpp"#include "pion/net/HTTPRequestWriter.hpp"#include "pion/net/HTTPResponseReader.hpp"

void FinishedResponseReading(pion::net::HTTPResponsePtr httpResponsePtr,
pion::net::TCPConnectionPtr tcpConnectionPtr,
const boost::system::error_code& errorCode_ref)
{
// ***************************
// this code is never reached!
// ***************************
std::cout << errorCode_ref << std::endl;
std::cout << httpResponsePtr->getContent() << std::endl;

tcpConnectionPtr->finish();
tcpConnectionPtr->close();
}void FinishedRequestSending(const boost::system::error_code& error_code_ref,
pion::net::TCPConnectionPtr tcpConnectionPtr,
pion::net::HTTPRequest* httpRequest_ptr)
{
// ***************************
// this code is never reached!
// ***************************
pion::net::HTTPResponseReader::FinishedHandler fh =
boost::bind(FinishedResponseReading, _1, _2, _3);
pion::net::HTTPResponseReaderPtr httpResponseReaderPtr =
pion::net::HTTPResponseReader::create(tcpConnectionPtr,
*httpRequest_ptr,
fh);
httpResponseReaderPtr->receive();
}int main()
{
boost::asio::io_service io_service;

// create and configure HTTPRequest
pion::net::HTTPRequest* httpRequest_ptr = new pion::net::HTTPRequest();
pion::net::HTTPRequestPtr httpRequestPtr(httpRequest_ptr);
httpRequest_ptr->setResource("/someService");
httpRequest_ptr->setMethod("PUT");

// create TCPConnection
pion::net::TCPConnection* tcpConnection_ptr =
new pion::net::TCPConnection(io_service);
pion::net::TCPConnectionPtr tcpConnectionPtr(tcpConnection_ptr);

// create HTTPRequestWriter
pion::net::HTTPRequestWriterPtr httpRequestWriterPtr(
pion::net::HTTPRequestWriter::create(tcpConnectionPtr,
httpRequestPtr,
boost::bind(FinishedRequestSending, _1,
tcpConnectionPtr,
httpRequest_ptr)));
// needed?
tcpConnection_ptr->setLifecycle(pion::net::TCPConnection::LIFECYCLE_KEEPALIVE);
// connect to server
tcpConnection_ptr->connect("192.168.1.14", 8080);
// send payload
httpRequestWriterPtr << "{\"someService\": \"something\"}";
httpRequestWriterPtr->send();

// ***********************************
// working fine so far! server is getting payload and is sending a HTTP Response
// but FinishedRequestSending is never reached
// ***********************************

// this is just to not exit immediately
boost::this_thread::sleep(boost::posix_time::milliseconds(15000));

// cleanup
delete(httpRequest_ptr);
delete(tcpConnection_ptr);

return 0;
}

2

Решение

Если вы хотите общаться синхронно, вы можете сделать что-то вроде этого:

int main()
{
boost::asio::io_service io_service
pion::net::TCPConnection tcpConnection(io_service);

pion::net::HTTPRequest httpRequest;
httpRequest.setResource("/server/resource");
httpRequest.setMethod("PUT");
httpRequest.setMinor(1);
httpRequest.setMajor(1);
httpRequest.setContent("test");

boost::system::error_code ec;
ec = tcpConnection.connect("192.168.1.1", 80); // blocks till connected or timed out
if (!ec)
{
httpRequest.send(tcpConnection, ec); // never blocks
if (!ec)
{
pion::net::HTTPResponse(httpRequest);
httpResponse.receive(tcpConnection, ec); // this might block forever :-(
// httpResponse.receive seems to be IO dependent, you can set your socket to timeout
if (!ec)
{
httpResponse.write(std::cout, ec);
}
}
}
}

Однако если вам нужен более сложный подход, вы можете pion::net::HTTPResponseReader ждать асинхронного ответа сервера.
заголовок:

class MyHTTPClient {
public:
void close();
pion::net::HTTPResponsePtr blockingReceiveOrTimeout(pion::net::HTTPRequest httpRequest, boost::system::error_code& ec_ref);
MyHTTPClient(boost::asio::ip::address aServerIP, unsigned int aServerPort);
virtual ~MyHTTPClient();
private:
boost::asio::ip::address            mp_serverIP;
unsigned int                    mp_serverPort;
boost::asio::io_service             mp_ioService;
pion::net::TCPConnectionPtr         mp_tcpConnectionPtr;
pion::net::HTTPResponsePtr          mp_curr_httpResponsePtr;
boost::system::error_code           mp_curr_errorCode;

void finishedReceiveResponse(pion::net::HTTPResponsePtr httpResponsePtr, const boost::system::error_code& error_code_ref);

};

каст:

MyHTTPClient::MyHTTPClient(boost::asio::ip::address aServerIP, unsigned int aServerPort) : mp_serverIP(aServerIP), mp_serverPort(aServerPort)
{
mp_tcpConnectionPtr.reset(new pion::net::TCPConnection(mp_ioService));
mp_tcpConnectionPtr->setLifecycle(pion::net::TCPConnection::LIFECYCLE_KEEPALIVE);
}

MyHTTPClient::~MyHTTPClient()
{
mp_tcpConnectionPtr->close();
}

void MyHTTPClient::close()
{
mp_tcpConnectionPtr->close();
}

pion::net::HTTPResponsePtr MyHTTPClient::blockingReceiveOrTimeout(pion::net::HTTPRequest httpRequest, boost::system::error_code& error_code_ref)
{
// reinit
mp_curr_httpResponsePtr.reset();
mp_ioService.reset();
error_code_ref.clear();

// connect to server if not already connectec
if (!mp_tcpConnectionPtr->is_open())
{
error_code_ref = mp_tcpConnectionPtr->connect(mp_serverIP, mp_serverPort);
}
if (!error_code_ref)
{
// send Request
httpRequest.send(*mp_tcpConnectionPtr.get(), error_code_ref, false);

if (!error_code_ref)
{
// asynchronously wait for response (times out automatically)
pion::net::HTTPResponseReader::FinishedHandler responseReaderFinishHandler = boost::bind(&MyHTTPClient::finishedReceiveResponse, this, _1, _3);
const pion::net::HTTPRequest constHTTPRequest = httpRequest;
pion::net::HTTPResponseReaderPtr httpResponseReaderPtr = pion::net::HTTPResponseReader::create(
mp_tcpConnectionPtr,
constHTTPRequest,
responseReaderFinishHandler);
httpResponseReaderPtr->receive();
mp_ioService.run();
}
}
return mp_curr_httpResponsePtr;
}

void MyHTTPClient::finishedReceiveResponse(pion::net::HTTPResponsePtr httpResponsePtr, const boost::system::error_code& error_code_ref)
{
mp_curr_httpResponsePtr = httpResponsePtr;
}
4

Другие решения

Код Мартина обновлен для PION 5.0.3:

httpClient.hpp:

#ifndef httpClient_HPP_INCLUDED
#define httpClient_HPP_INCLUDED

#include <pion/error.hpp>
#include <pion/http/response.hpp>
#include <pion/tcp/connection.hpp>
#include <pion/http/response_reader.hpp>
#include <boost/asio.hpp>

class httpClient
{
public:
void close();
pion::http::response_ptr blockingReceiveOrTimeout(pion::http::request httpRequest, boost::system::error_code& ec_ref);
httpClient(boost::asio::ip::address aServerIP, unsigned int aServerPort);
virtual ~httpClient();

private:
boost::asio::ip::address mp_serverIP;
unsigned int mp_serverPort;
boost::asio::io_service mp_ioService;
pion::tcp::connection_ptr mp_tcpConnectionPtr;
pion::http::response_ptr mp_curr_httpResponsePtr;
boost::system::error_code mp_curr_errorCode;

void finishedReceiveResponse(pion::http::response_ptr httpResponsePtr, const boost::system::error_code& error_code_ref);

};

#endif // httpClient_HPP_INCLUDED

httpClient.cpp:

#include "httpClient.hpp"
httpClient::httpClient(boost::asio::ip::address aServerIP, unsigned int aServerPort) : mp_serverIP(aServerIP), mp_serverPort(aServerPort)
{
mp_tcpConnectionPtr.reset(new pion::tcp::connection(mp_ioService));
mp_tcpConnectionPtr->set_lifecycle(pion::tcp::connection::LIFECYCLE_KEEPALIVE);
}

httpClient::~httpClient()
{
mp_tcpConnectionPtr->close();
}

void httpClient::close()
{
mp_tcpConnectionPtr->close();
}

pion::http::response_ptr httpClient::blockingReceiveOrTimeout(pion::http::request httpRequest, boost::system::error_code& error_code_ref)
{
// reinit
mp_curr_httpResponsePtr.reset();
mp_ioService.reset();
error_code_ref.clear();

// connect to server if not already connectec
if (!mp_tcpConnectionPtr->is_open())
{
error_code_ref = mp_tcpConnectionPtr->connect(mp_serverIP, mp_serverPort);
}
if (!error_code_ref)
{
// send Request
httpRequest.send(*mp_tcpConnectionPtr.get(), error_code_ref, false);

if (!error_code_ref)
{
// asynchronously wait for response (times out automatically)
pion::http::response_reader::finished_handler_t responseReaderFinishHandler = boost::bind(&httpClient::finishedReceiveResponse, this, _1, _3);
const pion::http::request constHTTPRequest = httpRequest;
pion::http::response_reader_ptr httpResponseReaderPtr = pion::http::response_reader::create(
mp_tcpConnectionPtr,
constHTTPRequest,
responseReaderFinishHandler);
httpResponseReaderPtr->receive();
mp_ioService.run();
}
}
return mp_curr_httpResponsePtr;
}

void httpClient::finishedReceiveResponse(pion::http::response_ptr httpResponsePtr, const boost::system::error_code& error_code_ref)
{
mp_curr_httpResponsePtr = httpResponsePtr;
}

для полноты main.cpp:

#include <iostream>
#include "httpClient.hpp"
int main (int argc, char *argv[])
{
pion::http::request request;
std::string requestData = "asdf";
request.set_content(requestData);
httpClient client(boost::asio::ip::address::from_string("10.1.1.100"), 80);
pion::http::response_ptr response;
boost::system::error_code ec;
response = client.blockingReceiveOrTimeout(request, ec);
response->write(std::cout, ec);
return 0;
}
2

Я не знаком с пион-сетью. Однако на основе версия Я думаю, что используется в соответствии с соглашениями об именах, быстрое сканирование кода pion-net выглядит так, как будто io_service.run() должен быть вызван в коде приложения. Единственное место, где я нашел pion-net, явно вызывающую io_service.run() был в PionScheduler типы, используемые Server типы.

1
По вопросам рекламы [email protected]