C++11 如何使用Boost::asio和Beast为所有http客户端线程维护单个会话并执行尽可能多的写和读操作? Http客户端与Boost:asio并行推送数据

C++11 如何使用Boost::asio和Beast为所有http客户端线程维护单个会话并执行尽可能多的写和读操作? Http客户端与Boost:asio并行推送数据,c++11,boost-asio,boost-beast,beast,C++11,Boost Asio,Boost Beast,Beast,我想尽快连接RestAPI服务器并发布数据。我发现Boost::asio提供了这种功能。通过使用示例代码,我构建了一些东西,但是随着1000多个请求,它开始崩溃。多个读取命令失败 #include <boost/beast/core.hpp> #include <boost/beast/http.hpp> #include <boost/beast/version.hpp> #include <boost/thread/thread.hpp> #i

我想尽快连接RestAPI服务器并发布数据。我发现Boost::asio提供了这种功能。通过使用示例代码,我构建了一些东西,但是随着1000多个请求,它开始崩溃。多个读取命令失败

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/thread/thread.hpp>
#include <boost/asio/strand.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <chrono>

namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>

void fail(beast::error_code ec, char const* what)
{
    std::cerr << what << ": " << ec.message() << "\n";
}

// Performs an HTTP GET and prints the response
class session : public std::enable_shared_from_this<session>
{
    tcp::resolver resolver_;
    beast::tcp_stream stream_;
    beast::flat_buffer buffer_; // (Must persist between reads)
    http::request<http::empty_body> req_;
    http::response<http::string_body> res_;
    boost::asio::strand<boost::asio::io_context::executor_type> strand_;

public:
    // Objects are constructed with a strand to
    // ensure that handlers do not execute concurrently.
    explicit
        session(std::shared_ptr< boost::asio::io_context >ioc)
        : resolver_(net::make_strand (*ioc))
        , stream_(net::make_strand(*ioc))
        , strand_(ioc->get_executor())
    {
    }

    // Start the asynchronous operation
    void run( char const* host,
            char const* port,
            char const* target,
            int version)
    {
        // Set up an HTTP GET request message
        req_.version(version);
        req_.method(http::verb::get);
        req_.target(target);
        req_.set(http::field::host, host);
        req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);

        // Look up the domain name
        resolver_.async_resolve(
            host,
            port,
            beast::bind_front_handler(
                &session::on_resolve,
                shared_from_this()));
    }

    void on_resolve(beast::error_code ec, tcp::resolver::results_type results)
    {
        if (ec)
            return fail(ec, "resolve");

        // Set a timeout on the operation
        stream_.expires_after(std::chrono::seconds(30));

        // Make the connection on the IP address we get from a lookup
        stream_.async_connect(
            results,
            beast::bind_front_handler(
                &session::on_connect,
                shared_from_this()));
    }

    void on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type)
    {
        if (ec)
            return fail(ec, "connect");

        // Set a timeout on the operation
        stream_.expires_after(std::chrono::seconds(60));

        // Send the HTTP request to the remote host
        http::async_write(stream_, req_,
            boost::asio::bind_executor(
                strand_,
                        beast::bind_front_handler(
                                &session::on_write,
                                shared_from_this())));
    }

    void on_write(beast::error_code ec, std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if (ec)
            return fail(ec, "write");

        // Receive the HTTP response
        http::async_read(stream_, buffer_, res_,
            boost::asio::bind_executor(
                strand_,
            beast::bind_front_handler(
                &session::on_read,
                shared_from_this())));
    }

    void on_read(beast::error_code ec, std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if (ec)
            return fail(ec, "read");

        // Write the message to standard out
        //std::cout << res_ << std::endl;

        // Gracefully close the socket
        stream_.socket().shutdown(tcp::socket::shutdown_both, ec);

        // not_connected happens sometimes so don't bother reporting it.
        if (ec && ec != beast::errc::not_connected)
            return fail(ec, "shutdown");

        // If we get here then the connection is closed gracefully
    }
};

class CHttpClient
{
private:
    boost::thread_group worker_threads;

    void Post()
    {
        auto client = std::make_shared<session>(ioc);
        client->run(m_sHost.c_str(), m_sPort.c_str(), m_sTarget.c_str(), 11);
    }

protected:
    std::string m_sHost;
    std::string m_sPort;
    std::string m_sTarget;
    const int VERSION = 11;

    
    std::shared_ptr< boost::asio::io_context > ioc;
    std::shared_ptr< boost::asio::io_context::work > work;
    std::shared_ptr<session> client;

public:
    
    CHttpClient(std::string sHost, std::string sPort, std::string sTarget) :
        m_sHost(sHost),
        m_sPort(sPort),
        m_sTarget(sTarget) 
    {
        
        ioc = std::make_shared<boost::asio::io_context>();
        work = std::make_shared<boost::asio::io_context::work>(*ioc);
        //client = std::make_shared<session>(ioc);
    }


    void Initialize(const int nThreadCount = 1)
    {
        
        for (int x = 0; x < nThreadCount; ++x)
        {
            std::function<void()> fun = [this]() { this->ioc->run(); };
            worker_threads.create_thread(
                //boost::bind(&CHttpClient::WorkerThread, this)
                boost::bind(fun)
            );
        }
        
        // add the main thread into the pool as well
        //this->ioc->run();
    }

    
    void PostRequest(const std::string& sTarget, const std::string& sVerb)
    {
        ioc->post(boost::bind(&CHttpClient::Post, this));
    }

    void Stop()
    {
        work.reset();
        worker_threads.join_all();
        ioc->stop();
    }

};


int main()
{
    auto const host = "localhost";              
    auto const port = "32773";                  
                                                
    auto const target = "/api/DeviceItems"; ;
    int version = 11; 
 
 
    CHttpClient objHttpClient(host, port, target);
    objHttpClient.Initialize(8);

    auto t1 = std::chrono::high_resolution_clock::now();

    for (int ii = 0; ii < 3000; ++ii)
        objHttpClient.PostRequest(target, "get");
 
    objHttpClient.Stop();
    
    auto t2 = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();

    std::cout << duration << " milliseconds";

    system("PAUSE");
    return EXIT_SUCCESS;
}

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
命名空间beast=boost::beast;//从…起
命名空间http=beast::http;//从…起
名称空间net=boost::asio;//从…起
使用tcp=boost::asio::ip::tcp;//从…起
无效失败(beast::错误代码ec,字符常量*什么)
{
标准:cerr