如何修复Boost::Asio客户端Http请求错误



我正试图通过观看此视频来精简C++的Boost::Asio网络库,但我坚持使用异步线程发出请求。

代码:

#include "stdafx.h"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ts/buffer.hpp>
#include <boost/asio/ts/internet.hpp>
#include <boost/system/error_code.hpp>
std::vector<char> vBuffrer(20 * 1024);
void GrabSomeData(boost::asio::ip::tcp::socket& socket) {
socket.async_read_some(boost::asio::buffer(vBuffrer.data(), vBuffrer.size()),
[&](std::error_code ec, std::size_t length)
//boost::system::error_code ec
{
if (!ec)
{
std::cout << "nnRead" << length << "bytesnn";
for (int i = 0; i < length; i++)
std::cout << vBuffrer[i];
GrabSomeData(socket);
}
});

}
int main()
{
boost::system::error_code ec;
boost::asio::io_context context;
boost::asio::io_context::work idleWork(context);
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address("13.107.21.200",ec),80);
boost::asio::ip::tcp::socket socket(context);
std::thread thrContext = std::thread([&]() {context.run(); });
std::cout << "Starting " << std::endl;
socket.connect(endpoint,ec);
if (!ec)
{
std::cout << "Connected ! " << std::endl;
}
else {
std::cout << "Fail to connect ! " << ec.message() << std::endl;
}
if (socket.is_open()) {
GrabSomeData(socket);
std::string sRequest =
"GET /index.html HTTP/1.1rn"
"Host: www.example.comrn"
"Connection: closernrn";
socket.write_some(boost::asio::buffer(sRequest.data(), sRequest.size()), ec);
using namespace std::chrono_literals;
std::this_thread::sleep_for(2800ms);
//std::this_thread::sleep_for(1ms);
context.stop();
if (thrContext.joinable()) thrContext.join();
}
system("pause");
return 0;
}

Microsoft Visual studio给我这个:

Error C2752 'asio_prefer_fn::call_traits<boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context &>,boost::asio::execution::detail::blocking::never_t<0>,boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0>>> &,void (const boost::asio::execution::detail::blocking::possibly_t<0> &,boost::asio::execution::allocator_t<std::allocator<void>>),void>': more than one partial specialization matches the template argument list  boostasiotest   c:boostboost_1_75_0boostasiodetailhandler_work.hpp    353

Error   C2893   Failed to specialize function template 'enable_if<asio_prefer_fn::call_traits<T,void(P0,P1,PN...),void>::overload==,call_traits<T,void(P0,P1,PN...),void>::result_type>::type asio_prefer_fn::impl::operator ()(T &&,P0 &&,P1 &&,PN &&...) noexcept(<expr>) const'  boostasiotest   c:boostboost_1_75_0boostasiodetailhandler_work.hpp    353

一切都很好,直到我添加了GrabSomeData函数,我完全不知道如何修复它,如果有任何帮助,我将不胜感激。

PS:Boost网站上有一个关于这个主题的例子,但它是面向对象的,所有的指针都指向这个类,我(认为(这无济于事。

就像评论者一样,我不能重新编译你的消息:它只是编译,

  • MSVC 19,/std:c++14,Boost 1.75.0:编译器资源管理器

现在,我查看其他问题:

  1. write_some可能不会写入所有数据-您需要确保一个组合的写入操作

  2. 竞赛条件:由于您在线程上执行GrabSomeData,因此需要同步对CCD_ 3和CCD_共享资源(。

    io_context本身是线程安全的。

    在这种情况下,很容易避免,因为您不需要启动异步操作,直到发送请求之后:

    write(socket, boost::asio::buffer(sRequest));
    GrabSomeData(socket);
    
  3. CCD_ 6具有与写入侧类似的问题。您将需要一个组合读取操作,该操作读取read_until(socket, buf, "rnrn")的预期输出,然后读取基于Content-Length标头、Connection: Close和其他内容的预期内容(想想分块编码(。

    您目前没有存储和访问响应的好方法。使用streambuf,一个单独的组合阅读会容易得多。

    如果你想真正稳定,可以使用Beast接收HTTP/1.1响应(甚至可以分块(,而不用担心它何时完成(库为你做这件事(:

    auto GrabSomeData(tcp::socket& socket) {
    http::response<http::string_body> res;
    auto buf = boost::asio::dynamic_buffer(vBuffer);
    http::read(socket, buf, res);
    return res;
    }
    

    哦,不要在线程上做这件事(无论如何,为什么会这样?它实际上只是引入了未定义的行为,没有任何好处(:

简化代码

在Coliru上直播

在MSVC:Godbolt上编译

#include <boost/asio.hpp>
#include <boost/beast/http.hpp>
#include <iostream>
#include <iomanip>
using boost::asio::ip::tcp;
std::vector<char> vBuffer; // TODO FIXME global variable
auto GrabSomeData(tcp::socket& socket) {
namespace http = boost::beast::http;
http::response<http::string_body> res;
auto buf = boost::asio::dynamic_buffer(vBuffer);
http::read(socket, buf, res);
return res;
}
int main() try {
boost::asio::io_context context;
std::cout << "Starting " << std::endl;
tcp::endpoint endpoint(boost::asio::ip::make_address("13.107.21.200"), 80);
tcp::socket   socket(context);
socket.connect(endpoint);
std::cout << "Connected" << std::endl;
std::string const sRequest = "GET /index.html HTTP/1.1rn"
"Host: www.example.comrn"
"Connection: closern"
"rn";
write(socket, boost::asio::buffer(sRequest));
auto response = GrabSomeData(socket);
std::cout << "Response body length: " << response.body().size() << std::endl;
std::cout << "Response headers: " << response.base() << std::endl;
std::cout << "Response body: " << std::quoted(response.body()) << std::endl;
context.run(); // run_for(10s) e.g.
} catch (boost::system::system_error const& se) {
std::cerr << "Error: " << se.code().message() << std::endl;
}

打印的样本:

Starting 
Connected
Response body length: 194
Response headers: HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
X-MSEdge-Ref: 0BstXYAAAAACeQ2y+botzQISiBe2U3iGCQ0hHRURHRTE0MDgARWRnZQ==
Date: Sun, 21 Mar 2021 22:39:02 GMT
Connection: close
Response body: "<h2>Our services aren't available right now</h2><p>We're working to restore all services as soon as possible. Please check back soon.</p>0BstXYAAAAACeQ2y+botzQISiBe2U3iGCQ0hHRURHRTE0MDgARWRnZQ=="

注意它确实使用了分块编码,这似乎是您没有预料到的。

感谢@she的回答和推荐,花了这么长时间,但我已经升级到新的Windows10Visual Studio 2019,以及Boost 1_76并解决了问题!

这些错误与代码完全无关!

最新更新