mercredi 4 mars 2020

boost::asio::io_context Socket Server + thread_group

I'm trying to make an https server based on sockets and distribute it into different streams. The server itself works fine, stably holds the load and processes requests if everything goes on the same thread. If I put it in different threads, then when testing under load (wrk), the server crashes... My code:

#include <cstdio>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>

#include <boost/thread.hpp>


#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>

#include <iostream>






typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;


class session
{
public:
    session(boost::asio::io_context& io_context,
        boost::asio::ssl::context& context)
        : socket_(io_context, context)
    {
    }

    ssl_socket::lowest_layer_type& socket()
    {
        return socket_.lowest_layer();
    }

    void start()
    {

        socket_.async_handshake(boost::asio::ssl::stream_base::server,
            boost::bind(&session::handle_handshake, this,
                boost::asio::placeholders::error));
    }

    void handle_handshake(const boost::system::error_code& error)
    {
        if (!error)
        {
            socket_.async_read_some(boost::asio::buffer(data_, max_length),
                boost::bind(&session::handle_read, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
        }
        else
        {
            delete this;
        }
    }

    int req_rah = 0;

    void handle_read(const boost::system::error_code& error,
        size_t bytes_transferred)
    {
        if (!error)
        {

        std::string  Result_test = "HTTP/1.1 200 OK\r\n" +
                std::string("Content-Length: 2\r\n") +
                std::string("Content-Type: text/html\r\n") +
                std::string("Connection: Closed\r\n\r\n") +
                std::string("ok") +
                std::string("\r\n");

            boost::asio::streambuf request_test;
            std::ostream request_stream_test(&request_test);

            request_stream_test << Result_test;

            boost::asio::write(socket_, request_test);

            boost::asio::async_write(socket_,
                request_test,
                boost::bind(&session::handle_write, this,
                    boost::asio::placeholders::error));




        }
        else
        {
            delete this;
        }
    }

    void handle_write(const boost::system::error_code& error)
    {
        if (!error)
        {
            socket_.async_read_some(boost::asio::buffer(data_, max_length),
                boost::bind(&session::handle_read, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
        }
        else
        {
            delete this;
        }
    }

private:
    ssl_socket socket_;
    enum { max_length = 6291456 };
    char data_[max_length] = "";
};

class server
{
public:
    server(boost::asio::io_context& io_context, unsigned short port)
        : io_context_(io_context),
        acceptor_(io_context,
            boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
        context_(boost::asio::ssl::context::sslv23)
    {
        context_.set_options(
            boost::asio::ssl::context::default_workarounds
            | boost::asio::ssl::context::no_sslv2
            | boost::asio::ssl::context::single_dh_use);
        context_.set_password_callback(boost::bind(&server::get_password, this));
        context_.use_certificate_chain_file("Server.crt");
        context_.use_private_key_file("Server.key", boost::asio::ssl::context::pem);
        context_.use_tmp_dh_file("dh2048.pem");

        start_accept();
    }

    std::string get_password() const
    {
        return "";
    }

    void start_accept()
    {



        session* new_session = new session(io_context_, context_);
        acceptor_.async_accept(new_session->socket(),
            boost::bind(&server::handle_accept, this, new_session,
                boost::asio::placeholders::error));
    }

    void handle_accept(session* new_session,
        const boost::system::error_code& error)
    {
        if (!error)
        {
            new_session->start();
        }
        else
        {
            delete new_session;
        }

        start_accept();
    }

private:
    boost::asio::io_context& io_context_;
    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::ssl::context context_;
};








int main(int argc,      
    char *argv[], 
    char *envp[])
{


    try
    {


        boost::asio::io_context io_context;
        boost::thread_group pool;



        server s(io_context, 8080);


        for (auto i = 0u; i<boost::thread::hardware_concurrency(); ++i)
            pool.create_thread([&] {io_context.run(); });

        pool.join_all();


    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }


    return 0;
}

when accessing from the browser https://127.0.0.1:8080 all the rules, I get "ok." When wrk is executed, everything crashes... As I understand, threads are being processed incorrectly (reading or/and answer), whoever faced a similar task, please help, what's wrong... Thanks in advance!

Aucun commentaire:

Enregistrer un commentaire