Boost Beast 异步读取参数过载或不匹配

问题描述 投票:0回答:1
 AsyncReadStream& stream,
 DynamicBuffer& buffer,
 basic_parser< isRequest >& parser,
 ReadHandler&& handler = net::default_completion_token_t< executor_type< AsyncReadStream > >{});

根据上述内容,我是否在下面的异步读取中遗漏了一些内容?因为没有 抛出了重载函数错误的实例

void hook::connector(std::string id){
    boost::system::error_code ec;
    
    auto stream_socket=std::make_shared<boost::beast::tcp_stream>(boost::asio::make_strand(ioc));

    boost::beast::flat_buffer read_buffer;

    boost::beast::http::request<boost::beast::http::string_body> con_req;

    boost::beast::http::response<boost::beast::http::string_body> con_res;

    boost::asio::ip::tcp::endpoint endP = this->select_endP(servers[id].endpoint_pool, servers[id].domain);

    stream_socket->expires_after(std::chrono::seconds(30));

    try {
        stream_socket->async_connect(endP, [this, id, stream_socket,&read_buffer,con_req, con_res](boost::system::error_code ec) {
            if (!ec) {
                std::cout << "Connected to server!" << std::endl;

                stream_socket->expires_after(std::chrono::seconds(30));

                boost::beast::http::async_write(*stream_socket,con_req,
                    [this, id, stream_socket,&read_buffer,con_req,con_res](boost::system::error_code ec, std::size_t bytes_transferred) {
                        boost::ignore_unused(bytes_transferred);
                        
                        if (!ec) {

                            read_buffer.clear();



//error is being raised from this snippet
                            boost::beast::http::async_read(*stream_socket,read_buffer,con_res,[this,id,con_res](boost::system::error_code ec,std::size_t transfered_size){
                                boost::ignore_unused(transfered_size);

                                if(!ec){
                                    //success
                                } else{
                                    //failure
                                };

                            });

                            if (con_req.need_eof()) {

                                boost::beast::error_code shutdown_ec;

                                stream_socket->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, shutdown_ec);

                                if(shutdown_ec) {

                                    cout << "Error shutting down: " << shutdown_ec.message() << endl;

                                }
                            };

                        } else {
                            std::cout << "Error writing: " << ec.message() << std::endl;
                            // Retry the connection on failure
                        }
                    }
                );
            } else {
                std::cout << "Error connecting: " << ec.message() << std::endl;
                // Retry the connection on failure
            }
        });
    } catch (const std::exception& e) {
        std::cout << "Error with read and write: " << e.what() << std::endl;
    }

};
c++ boost c++17 boost-asio boost-beast
1个回答
0
投票

您正在通过不可变的 lambda 表达式按值捕获多个对象。除了这没有做你需要的事情之外,这还意味着对象是

const
(不可变)。

这就是为什么

con_res
不能与
async_read
一起使用:它无法转换为对消息对象(或解析器)的可变引用。

“修复”编译器错误的一种偶然方法是使 lambda 可变:

住在Coliru

Live On Compiler Explorer(两者都耗尽了资源)

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <map>
namespace asio = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using asio::ip::tcp;

struct hook {
    void             connector(std::string id);
    asio::io_context ioc;

    struct Server {
        std::string                domain;
        std::vector<tcp::endpoint> endpoint_pool;
    };

    std::map<std::string, Server> servers{
        {"test",
         Server{
             "www.google.com",
             {
                 {tcp::endpoint{{}, 8989}},
                 {tcp::endpoint{{}, 9090}},
                 {tcp::endpoint{{}, 9191}},
             },
         }},
    };

    tcp::endpoint select_endP(std::vector<tcp::endpoint> const& endpoint_pool, std::string /*domain*/) {
        return endpoint_pool[0]; // TODO: implement selection logic
    }
};

void hook::connector(std::string id) {
    boost::system::error_code ec;

    auto stream_socket = std::make_shared<beast::tcp_stream>(make_strand(ioc));

    beast::flat_buffer read_buffer;

    http::request<http::string_body> con_req;
    http::response<http::string_body> con_res;

    tcp::endpoint endP = this->select_endP(servers[id].endpoint_pool, servers[id].domain);

    stream_socket->expires_after(std::chrono::seconds(30));

    try {
        stream_socket->async_connect(
            endP, [this, id, stream_socket, &read_buffer, con_req, con_res](boost::system::error_code ec) {
                if (!ec) {
                    std::cout << "Connected to server!" << std::endl;

                    stream_socket->expires_after(std::chrono::seconds(30));

                    http::async_write(
                        *stream_socket, con_req,
                        [this, id, stream_socket, &read_buffer, con_req,
                         con_res](beast::error_code ec, std::size_t bytes_transferred) mutable {
                            boost::ignore_unused(bytes_transferred);

                            if (!ec) {

                                read_buffer.clear();

                                // error is being raised from this snippet
                                http::async_read(
                                    *stream_socket, read_buffer, con_res,
                                    [this, id /*, con_res*/](beast::error_code ec,
                                                             std::size_t       transfered_size) mutable {
                                        boost::ignore_unused(transfered_size);

                                        if (!ec) {
                                            // success
                                        } else {
                                            // failure
                                        };
                                    });

                                if (con_req.need_eof()) {

                                    beast::error_code shutdown_ec;

                                    stream_socket->socket().shutdown(tcp::socket::shutdown_send, shutdown_ec);

                                    if (shutdown_ec) {

                                        std::cout << "Error shutting down: " << shutdown_ec.message()
                                                  << std::endl;
                                    }
                                };

                            } else {
                                std::cout << "Error writing: " << ec.message() << std::endl;
                                // Retry the connection on failure
                            }
                        });
                } else {
                    std::cout << "Error connecting: " << ec.message() << std::endl;
                    // Retry the connection on failure
                }
            });
    } catch (std::exception const& e) {
        std::cout << "Error with read and write: " << e.what() << std::endl;
    }
};

int main() {
    hook h;
    h.connector("test");
}

然而,实际上,您最终总是会得到

con_req
con_res
的空副本。您真正想要的是共享这些内容。例如:

住在科里鲁

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <map>
namespace asio = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using asio::ip::tcp;

struct hook {
    void              connector(std::string id);
    asio::thread_pool ioc;

    struct Server {
        std::string                domain;
        std::vector<tcp::endpoint> endpoint_pool;
    };

    std::map<std::string, Server> servers{
        {"test",
         Server{
             "www.google.com",
             {
                 {tcp::endpoint{{}, 8989}},
                 {tcp::endpoint{{}, 9090}},
                 {tcp::endpoint{{}, 9191}},
             },
         }},
    };

    tcp::endpoint select_endP(std::vector<tcp::endpoint> const& endpoint_pool, std::string /*domain*/) {
        return endpoint_pool[0]; // TODO: implement selection logic
    }
};

void hook::connector(std::string id) {
    struct Con {
        beast::tcp_stream                 stream_socket;
        std::string                       id;
        beast::flat_buffer                read_buffer = {};
        http::request<http::string_body>  con_req= {};
        http::response<http::string_body> con_res     = {};
    };
    auto state = std::make_shared<Con>(Con{beast::tcp_stream{make_strand(ioc)}, id});

    tcp::endpoint endP = this->select_endP(servers[id].endpoint_pool, servers[id].domain);

    state->stream_socket.expires_after(std::chrono::seconds(30));

    try {
        state->stream_socket.async_connect(
            endP, [state, id](boost::system::error_code ec) {
                if (!ec) {
                    std::cout << "Connected to server!" << std::endl;

                    state->stream_socket.expires_after(std::chrono::seconds(30));

                    http::async_write(
                        state->stream_socket, state->con_req,
                        [id, state](beast::error_code ec, size_t bytes_transferred) mutable {
                            boost::ignore_unused(bytes_transferred);

                            if (!ec) {

                                state->read_buffer.clear();

                                // error is being raised from this snippet
                                http::async_read(
                                    state->stream_socket, state->read_buffer, state->con_res,
                                    [state, id](beast::error_code ec, size_t transfered_size) mutable {
                                        boost::ignore_unused(transfered_size);

                                        if (!ec) {
                                            // success
                                        } else {
                                            // failure
                                        };
                                    });

                                if (state->con_req.need_eof()) {

                                    beast::error_code shutdown_ec;

                                    state->stream_socket.socket().shutdown(tcp::socket::shutdown_send,
                                                                           shutdown_ec);

                                    if (shutdown_ec) {
                                        std::cout << "Error shutting down: " << shutdown_ec.message()
                                                  << std::endl;
                                    }
                                };

                            } else {
                                std::cout << "Error writing: " << ec.message() << std::endl;
                                // Retry the connection on failure
                            }
                        });
                } else {
                    std::cout << "Error connecting: " << ec.message() << std::endl;
                    // Retry the connection on failure
                }
            });
    } catch (std::exception const& e) {
        std::cout << "Error with read and write: " << e.what() << std::endl;
    }
};

int main() {
    hook h;
    h.connector("test");
}

当然,正如您已经意识到的那样(因为您捕获了

this
),将操作作为
Con
类的一部分更有意义。

© www.soinside.com 2019 - 2024. All rights reserved.