boost beast http::read 一直阻塞不返回,问题解决, 使用parser对象的skip(true) 来解决

发布时间 2023-12-18 14:15:47作者: 元几科技

用beast 作为客户端发送http请求后读web服务端返回的数据,遇到了http::read 或http::async_read一直阻塞着,不返回,直到连接过期后被强制网络断开后read函数才返回。 看了官方文档,文档里这么描述的,read要一直等到end_of_stream时才回退出阻塞状态。也就是 连接失效后才行。

但我们的场景一般是要保持连接的,以供下次使用。

继续系统的读完官方文档后发现,http::read函数可以使用parser作为参数而不是直接用response,而parser对象提供了一个skip(true)函数,为true时,表明这次读返回的http消息只有http头没有body,所以在读完http header后,parser就告知http::read要退出阻塞状态。相关部分代码如下所示:

我遇到这个问题的场景是beast 作为客户端发送http请求连接一个http proxy,连接proxy后再与真实的目标服务器连接。

 

// // Send an HTTP CONNECT request to the proxy
http::request<http::empty_body> req{ http::verb::connect, "www.baidu.com:443", 11 };
req.set(http::field::host, "image.baidu.com");
req.set(http::field::user_agent, "curl/7.81.0");
req.set(http::field::proxy_connection, "Keep-Alive");
req.prepare_payload();
vlogi<<"my connect request is:"<<req<<std::endl;
//http::write(beast::get_lowest_layer(stream_), req);
http::write(stream_.next_layer(), req);

boost::beast::flat_buffer buffer;
//http::response<http::empty_body> res;
//res.result(http::status::unknown);
//res.version(10);

http::parser<false, http::empty_body> p;
p.skip(true);
//http::read(beast::get_lowest_layer(stream_), buffer_, p);

std::size_t result = -1;
//result = http::read(beast::get_lowest_layer(stream_), buffer_, res);
//result = http::read(beast::get_lowest_layer(stream_), buffer_, res);
//result = http::read(beast::get_lowest_layer(stream_), buffer_, p);
result = http::read(stream_.next_layer(), buffer_, p);

http::response<http::empty_body> && res = p.release();

vlogi <<"res after read:"<< res <<", buffer_.size:"<<buffer_.size()<<", result:"<<result<<", p.is_done:"<<p.is_done()<< std::endl;

// Check if the CONNECT request was successful (HTTP 200 OK)
if (res.result() != http::status::ok) {
vlogw << "CONNECT request failed with status code: " << res_.result_int() << std::endl;
return;
}
else
{
vlogi<<"connect to hproxy succeeed."<<std::endl;
}


// Perform the SSL handshake
stream_.async_handshake(
ssl::stream_base::client,
beast::bind_front_handler(
&client_ssl_session_http_proxy::on_handshake,
shared_from_this()));