отправить запрос http от клиента торнадо на асинхронный сервер cpp-netlib

У меня есть http-клиент, который я написал на python в рамках торнадо:

http_client = httpclient.HTTPClient()
request = httpclient.HTTPRequest("http://127.0.0.1:8000", method='PUT', body=str("data"))
response = http_client.fetch(request)

с другой стороны, у меня есть асинхронный сервер, который я написал на c ++, используя cpp-netlib. В основном он должен прочитать запрос и распечатать его тело

class Server;
typedef http::async_server<Server> server;

class Server {
public:
void operator()(server::request const & request, server::connection_ptr connection)
{
boost::shared_ptr<connection_handler> h(new connection_handler());
(*h)(request, connection);

server::response_header headers[] = { {"Connection","close"} ,{"Content-Type", "text/plain"} };
connection->set_headers(boost::make_iterator_range(headers, headers+2));
connection->set_status(server::connection::accepted);
connection->write("helloworld");
}

int main()
{
Server handler;
server::options options(handler);
server instance(
options.thread_pool(boost::make_shared<utils::thread_pool>(5))
.address("0.0.0.0")
.port("8000"));

instance.run();
return 0;
}

и обработчик соединения выглядит так:

struct connection_handler : boost::enable_shared_from_this<connection_handler>
{

struct read_post_callback
{
typedef boost::shared_ptr<connection_handler> handler_ptr_t;
read_post_callback(handler_ptr_t  handler_ptr) : handler(handler_ptr) {}

void operator()(server::connection::input_range range, boost::system::error_code error, size_t size, server::connection_ptr conn)
{
handler->read_sofar += size;
handler->cond.notify_one();
}

handler_ptr_t handler;
};

void operator()(server::request const &req, server::connection_ptr conn)
{
int cl;
server::request::headers_container_type const &hs = req.headers;
for(server::request::headers_container_type::const_iterator it = hs.begin(); it!=hs.end(); ++it)
{
if(boost::to_lower_copy(it->name)=="content-length")
{
cl = boost::lexical_cast<int>(it->value);
break;
}
}
cout<< req.body << endl;
read_sofar = 0;
while(read_sofar<cl)
{
boost::unique_lock<boost::mutex> lock(mtx);
server::connection::read_callback_function cc = read_post_callback(shared_from_this());
conn->read(cc);

cond.wait(lock);
}
}

int read_sofar;
boost::condition_variable cond;
boost::mutex mtx;
};

Но тело запроса всегда пустое, и вместо ответа, который я отправляю назад («привет мир»), большую часть времени я получаю что-то вроде этого (число может быть другим)

Ошибка: HTTP 0: неизвестно

Можете ли вы сказать мне, почему тело пусто или ответ не достигает?

РЕДАКТИРОВАТЬ:

Почему тело было пустым — в ответе. Что я делал неправильно, что не получал ответ, так это: я устанавливал состояние соединения после установки заголовков соединения на моем сервере. Просто поменялись местами, и это сработало как шарм.

server::response_header headers[] = { {"Connection","close"} ,{"Content-Type", "text/plain"} };

connection->set_status(server::connection::accepted);
connection->set_headers(boost::make_iterator_range(headers, headers+2));
connection->write("helloworld");

2

Решение

С помощью cpp-netlib асинхронное чтение должно выполняться следующим образом. req.body не загружается с данными, считанными из асинхронных. Так что нужно иметь свой собственный держатель для данных.

struct connection_handler : boost::enable_shared_from_this<connection_handler>
{
std::string                 body;
boost::condition_variable   cond;
boost::mutex                mtx;
size_t                      read_sofar;

connection_handler(const server::request& req, const server::connection_ptr& conn) :
conn(conn),
body("")
{
}

~connection_handler()
{
}

void operator()(const server::request& req, const server::connection_ptr& conn)
{
size_t cl = 0;
auto const& hs = req.headers;
for (auto it = hs.begin(); it != hs.end(); ++it)
{
if (boost::to_lower_copy(it->name)=="content-length")
{
cl = boost::lexical_cast<size_t>(it->value);
break;
}
}

read_sofar = 0;
while (read_sofar < cl)
{
boost::unique_lock<boost::mutex> lock(mtx);
read_chunk(cl - read_sofar, conn);

LogTrace(("gonna wait"));
cond.wait(lock);
LogTrace(("wokeup"));
}
}

void read_chunk(size_t left2read, server::connection_ptr conn)
{
LogTrace(("left2read: %ld", left2read));
conn->read(
boost::bind(
&connection_handler::handle_post_read,
connection_handler::shared_from_this(),
_1, _2, _3, conn, left2read
)
);
}

void handle_post_read(server::connection::input_range range,
boost::system::error_code error,
size_t size,
server::connection_ptr conn,
size_t left2read)
{
if (!error)
{
LogTrace(("readSize: %ld", size));
body.append(boost::begin(range), size);
size_t left = left2read - size;
read_sofar += size;
if (left > 0)
{
read_chunk(left, conn);
}
else
{
cond.notify_one();
}
}
LogTrace((error.message()));
}
};

Также вы можете изменить BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE определяется в boost/network/protocol/http/serversync_connection.hpp на более высокое значение, так что вы можете избежать нескольких переключений контекста. Это не настраивается в настоящее время.

3

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

Других решений пока нет …

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