gpt4 book ai didi

c++ - 提升 asio : Unable to read URL Body (JSON)

转载 作者:可可西里 更新时间:2023-11-01 17:01:19 25 4
gpt4 key购买 nike

我测试了以下 Boost::Asio 最小 HTTP 服务器示例:( Minimal HTTP Server based on Boost:Asio )

我能够成功收集诸如 Content-Length 之类的 Header 信息,但是当我尝试读取 Body 信息时该示例挂起。这是尝试读取正文信息的函数:

static void read_body(std::shared_ptr<session> pThis) {
info("read_body");

int nbuffer = pThis->headers.content_length();
std::shared_ptr<std::vector<char>> bufptr = std::make_shared<std::vector<char>>(nbuffer);
asio::async_read(pThis->socket, boost::asio::buffer(*bufptr, nbuffer),
[pThis](const error_code& e, std::size_t s)
{
info("read body complete");
});
}

我已经使用 libmicrohttpd 的解决方案成功读取了相同的 Body 信息。

是否有更正确的方法来使用 Boost:ASIO 读取 Body (JSON) 信息?

最佳答案

问题的本质是双重的:

  • 首先,有Undefined Behaviour因为您未能在完成处理程序中捕获 bufptr,这意味着该 vector 在系统调用写入时已被释放...

  • 其次,您正在“丢弃”正文的第一部分,因为您在阅读标题时已经收到了它。您应该添加代码以保留已在 read_next_line 中收到的部分。

真正的“误导”可能是在使用

asio::async_read_until(pThis->socket, pThis->buff, '\r', ...

好像它会以某种方式接收到一行。套接字不能那样工作。你会收到一个包裹。 TCP 堆栈决定什么构成数据包。 Asio 只是 promise 读取“直到”数据包>包含<定界符。它并没有说它不会接收更多,它只是没有安排另一个接收操作。

因此,要真正修复它,您可以一次读取所有 header :

asio::async_read_until(pThis->socket, pThis->buff, "\r\n\r\n", 
[pThis](const error_code &e, std::size_t s) {
if (e) { std::cerr << "Error:" << __LINE__ << " " << e.message() << "\n"; return; }
std::cout << __FILE__ << ":" << __LINE__ << " received:" << s << "\n";
std::istream is(&pThis->buff);

std::string line, ignore;

if (getline(is, line, '\r') && is.ignore(1, '\n'))
pThis->headers.on_read_request_line(line);

while (getline(is, line, '\r') && is.ignore(1, '\n') && !line.empty())
pThis->headers.on_read_header(line);

注意 同样,重要的是不要假设报头结尾与数据包边界重合。因此,开始 read_body() 时耗尽已收到的可用输入:

    std::shared_ptr<std::vector<char> > bufptr = std::make_shared<std::vector<char> >(nbuffer);

auto partial = std::copy(
std::istreambuf_iterator<char>(&pThis->buff), {},
bufptr->begin());

std::size_t already_received = std::distance(bufptr->begin(), partial);

assert(nbuffer >= already_received);
nbuffer -= already_received;

固定演示

Live On Coliru

#include <boost/asio.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <string>
#include <memory>
#include <iostream>
#include <fstream>

using namespace boost;
using namespace boost::system;
using namespace boost::asio;

unsigned char *get_icon(int *pOutSize);

class session;

class http_headers {
std::string method;
std::string url;
std::string version;

std::map<std::string, std::string> headers;

public:
std::string get_response() {
std::stringstream ssOut;
if (url == "/favicon.ico") {
int nSize = 0;
unsigned char *data = get_icon(&nSize);

ssOut << "HTTP/1.1 200 OK" << std::endl;
ssOut << "content-type: image/vnd.microsoft.icon" << std::endl;
ssOut << "Content-Length: " << nSize << std::endl;
ssOut << std::endl;

ssOut.write((char *)data, nSize);
} else if (url == "/") {
std::string sHTML = "<html><body><h1>Hello World</h1><p>This is a test web server in c++</p></body></html>";
ssOut << "HTTP/1.1 200 OK" << std::endl;
ssOut << "Content-Type: text/html" << std::endl;
ssOut << "Content-Length: " << sHTML.length() << std::endl;
ssOut << std::endl;
ssOut << sHTML;
} else {
std::string sHTML = "<html><body><h1>404 Not Found</h1><p>There's nothing here.</p></body></html>";
ssOut << "HTTP/1.1 404 Not Found" << std::endl;
ssOut << "Content-Type: text/html" << std::endl;
ssOut << "Content-Length: " << sHTML.length() << std::endl;
ssOut << std::endl;
ssOut << sHTML;
}
return ssOut.str();
}

size_t content_length() {
auto request = headers.find("Content-Length");
if (request != headers.end()) {
std::stringstream ssLength(request->second);
size_t content_length;
ssLength >> content_length;
return content_length;
}
return 0;
}

void on_read_header(std::string line) {
std::cout << "header: '" << line << "'\n";

std::stringstream ssHeader(line);
std::string headerName;
std::getline(ssHeader, headerName, ':');

std::string value;
std::getline(ssHeader, value);
headers[headerName] = value;
}

void on_read_request_line(std::string line) {
std::stringstream ssRequestLine(line);
ssRequestLine >> method;
ssRequestLine >> url;
ssRequestLine >> version;

std::cout << "request for resource: " << url << std::endl;
}
};

namespace {
static void info(std::string s) { std::cout << "INFO:" << s << "\n"; }
}

class session {
asio::streambuf buff;
http_headers headers;

static void read_body(std::shared_ptr<session> pThis) {

info("read_body");

size_t nbuffer = pThis->headers.content_length();
std::cout << __FILE__ << ":" << __LINE__ << " nbuffer:" << nbuffer << "\n";

std::shared_ptr<std::vector<char> > bufptr = std::make_shared<std::vector<char> >(nbuffer);

auto partial = std::copy(
std::istreambuf_iterator<char>(&pThis->buff), {},
bufptr->begin());

std::size_t already_received = std::distance(bufptr->begin(), partial);

assert(nbuffer >= already_received);
nbuffer -= already_received;

asio::async_read(pThis->socket, boost::asio::buffer(&*bufptr->begin() + already_received, nbuffer),
[=](const error_code &e, std::size_t s) {
info("read body complete");
// EOF is to be expected on client disconnect
if (e && e != boost::asio::error::eof) {
std::cerr << "Error:" << __LINE__ << " " << e.message() << "\n"; return;
}

std::cout << __FILE__ << ":" << __LINE__ << " received:" << s << "/" << nbuffer << "\n";

std::string body(&*bufptr->begin(), already_received + s);

std::string::size_type p = 0;
for (int i = 0; i<2; ++i)
p = body.find_last_of("\r\n", p-1);

std::cout << "Tail: '" << body.substr(p+1) << "'\n";

{
std::ofstream ofs("debug.txt", std::ios::binary);
ofs << body;
ofs << "\n" << __FILE__ << ":" << __LINE__ << " received:" << s << "/" << nbuffer << "\n";
}
});
}

static void read_headers(std::shared_ptr<session> pThis) {
asio::async_read_until(pThis->socket, pThis->buff, "\r\n\r\n",
[pThis](const error_code &e, std::size_t s) {
if (e) { std::cerr << "Error:" << __LINE__ << " " << e.message() << "\n"; return; }
std::cout << __FILE__ << ":" << __LINE__ << " received:" << s << "\n";
std::istream is(&pThis->buff);

std::string line, ignore;

if (getline(is, line, '\r') && is.ignore(1, '\n'))
pThis->headers.on_read_request_line(line);

while (getline(is, line, '\r') && is.ignore(1, '\n') && !line.empty())
pThis->headers.on_read_header(line);

if (pThis->headers.content_length()) {
pThis->read_body(pThis);

auto str = std::make_shared<std::string>("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
asio::async_write(
pThis->socket, boost::asio::buffer(*str),
[pThis, str](const error_code &e, std::size_t s) {
std::cout << "done" << std::endl;
});
} else {
std::shared_ptr<std::string> str = std::make_shared<std::string>(pThis->headers.get_response());
asio::async_write(
pThis->socket, boost::asio::buffer(*str),
[pThis, str](const error_code &e, std::size_t s) {
std::cout << "done" << std::endl;
});
}
});
}

public:
ip::tcp::socket socket;

session(io_service &io_service) : socket(io_service) {}

static void interact(std::shared_ptr<session> pThis) { read_headers(pThis); }
};

void accept_and_run(ip::tcp::acceptor &acceptor, io_service &io_service) {
std::shared_ptr<session> sesh = std::make_shared<session>(io_service);
acceptor.async_accept(sesh->socket, [sesh, &acceptor, &io_service](const error_code &accept_error) {
accept_and_run(acceptor, io_service);
if (accept_error) {
std::cerr << "Accept error: " << accept_error.message() << "\n";
} else {
session::interact(sesh);
}
});
}

int main() {
io_service io_service;
ip::tcp::endpoint endpoint{ ip::tcp::v4(), 8181 };
ip::tcp::acceptor acceptor{ io_service, endpoint };

acceptor.listen();
accept_and_run(acceptor, io_service);

io_service.run();
}

unsigned char icon_data[] = {
// reserved
0x00, 0x00,
// icon type (1 = icon)
0x01, 0x00,
// number of images (1)
0x01, 0x00,
// width, height (16x16)
0x10, 0x10,
// size of colour palette
0x00,
// reserved
0x00,
// colour planes (1)
0x01, 0x00,
// bits per pixel (32)
0x20, 0x00,

// size of data in bytes
0x28, 0x04, 0x00, 0x00,

// offset of bitmap data
0x16, 0x00, 0x00, 0x00,

// BEGIN BITMAPINFOHEADER
// bcsize
0x28, 0x00, 0x00, 0x00, // biSize
0x10, 0x00, 0x00, 0x00, // biWidth
0x20, 0x00, 0x00, 0x00, // biHeight (with both AND and XOR mask? wtf?)

0x01, 0x00, // biPlanes
0x20, 0x00, // biBitCount (32)

0x00, 0x00, 0x00, 0x00, // biCompression
0x00, 0x00, 0x00, 0x00, // biSizeImage
0x00, 0x00, 0x00, 0x00, // biXPelsPerMeter
0x00, 0x00, 0x00, 0x00, // biYPelsPerMeter
0x00, 0x00, 0x00, 0x00, // biClrUsed
0x00, 0x00, 0x00, 0x00, // biClrImportant
// END BITMAPINFOHEADER

// BITMAP DATA (4 bytes per pixel)
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,

0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF
};

unsigned char *get_icon(int *pOut) {
*pOut = sizeof(icon_data);
return icon_data;
}

关于c++ - 提升 asio : Unable to read URL Body (JSON),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33133316/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com