如何修复Boost :: Asio Client Http请求错误? [英] How to fix Boost::Asio Client Http request error?

查看:224
本文介绍了如何修复Boost :: Asio Client Http请求错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试通过观看 Boost :: Asio C ++网络库="https://www.youtube.com/watch?v=2hNdkYInj4g" rel ="nofollow noreferrer">视频,但我坚持使用异步方式发出请求.

I'm trying to lean Boost::Asio networking library for C++ by watching this video but I stuck at making request using threads asynchronously.

代码:

#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给我这个:

Microsoft Visual studio give me this :

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 函数,而且我完全不知道如何解决它,任何帮助将不胜感激.

Everything worked fine till I added GrabSomeData function and I have absolutely no idea how to fix it , any help would be appreciated.

PS::在Boost网站上有一个示例,该

PS : there is an example on the Boost website on this subject, but it is object oriented and all the pointers are referring to the class and I (think) it can't help.

推荐答案

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

Like the commenter, I cannot repro your message: it just compiles,

现在,我愿意看到其他问题:

Now, I do see other issues:

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

  1. write_some may not write all the data - you will want to ensure a composed-write operation

竞争条件:由于您正在线程上执行 GrabSomeData ,因此您需要同步对 tcp :: socket buffer (共享资源).

a race condition: since you're doing GrabSomeData on a thread, you need to synchronize access to the tcp::socket and buffer (the shared resources).

io_context 本身是线程安全的.

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

In this case, it's really easy to avoid, since you don't need to start the async operation until after you sent the request:

write(socket, boost::asio::buffer(sRequest));
GrabSomeData(socket);

  • async_read_some 具有与写端类似的问题.您将需要一个组合的读取操作,该操作读取预期的输出,以便 read_until(socket,buf,``\ r \ n \ r \ n"),然后根据读取多少内容> Content-Length 标头, Connection:Close 和其他(请考虑分块编码).

  • async_read_some has a similar problem as the write side. You will want a composed read operation that reads the expected output so read_until(socket, buf, "\r\n\r\n") and then read how much content is expected based on Content-Length header, Connection: Close and others (think chunked encoding).

    您目前没有好的方法来存储和访问响应.使用streambuf(一个单一的阅读片段)会容易得多.

    You currently have no good way to store and access the response. It would be a lot easier to use a streambuf, a single composed read.

    如果您想变得牢固,请使用Beast接收HTTP/1.1响应(甚至可以分块),而不用担心它何时完成(库会为您完成):

    If you want to be really solid, use Beast to receive a HTTP/1.1 response (which can even be chunked) and not worry about when it's complete (the library does it for you):

    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;
    }
    

    哦,不要在线程上执行它(为什么呢?它只是引入了未定义的行为而没有收获)

    Oh, and don't do it on a thread (why was that anyways? it literally just introduced undefined behavior for no gain):

    简化代码

    在Coliru上直播

    Simplified Code

    Live On Coliru

    在MSVC上进行编译:Godbolt

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

    注意它确实使用了分块编码,您似乎并没有期待.

    NOTE It does indeed use chunked encoding, which you didn't seem to be anticipating.

    这篇关于如何修复Boost :: Asio Client Http请求错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆