【问题标题】:How to fix Boost::Asio Client Http request error?如何修复 Boost::Asio Client Http 请求错误?
【发布时间】:2021-06-18 04:42:20
【问题描述】:

我正在尝试通过观看 video 来精简 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 << "\n\nRead" << length << "bytes\n\n";

            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.1\r\n"
            "Host: www.example.com\r\n"
            "Connection: close\r\n\r\n";
        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:\boost\boost_1_75_0\boost\asio\detail\handler_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:\boost\boost_1_75_0\boost\asio\detail\handler_work.hpp    353

在我添加 GrabSomeData 函数之前一切正常,但我完全不知道如何修复它,我们将不胜感激。

PS :subject 的 Boost 网站上有一个示例,但它是面向对象的,所有指针都指向该类,我(认为)它无济于事.

【问题讨论】:

  • 不编译“致命错误:stdafx.h:没有这样的文件或目录”
  • 你是在Linux上编译的吗?
  • 是的;请使用标准标题
  • 它是 Windows 的标准,stdafx.h 是 Windows 的东西。如果我从标题中删除它,它不会在 Visual Studio 上编译。并不是我喜欢它在 Windows 上,但教程就是这样,而且 Boost 应该是跨平台的!
  • 仅供参考,在这里编译/链接/运行良好(显然没有 stdafx.h)

标签: c++ multithreading boost boost-asio


【解决方案1】:

像评论者一样,我无法复制您的消息:它只是编译,

现在,我确实看到了其他问题:

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

  2. 竞争条件:由于您在线程上执行GrabSomeData,因此您 需要同步访问tcp::socketbuffer( 共享资源)。

    io_context 本身是线程安全的。

    在这种情况下,很容易避免,因为您不需要 在您发送请求之前开始异步操作:

    write(socket, boost::asio::buffer(sRequest));
    GrabSomeData(socket);
    
  3. async_read_some 与写入端有类似的问题。您将需要一个组合读取操作来读取预期的输出,例如 read_until(socket, buf, "\r\n\r\n"),然后根据 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;
    }
    

    哦,不要在线程上这样做(为什么会这样?它实际上只是引入了未定义的行为而没有任何收获):

简化代码

Live On Coliru

Compiles on 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.1\r\n"
        "Host: www.example.com\r\n"
        "Connection: close\r\n"
        "\r\n";

    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=="

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

【讨论】:

    【解决方案2】:

    感谢@sehe 的回答和建议,花了很长时间,但我已经升级到新的 Windows10Visual Studio 2019,以及 Boost 1_76问题解决了!

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-27
      相关资源
      最近更新 更多