Async принять с Boost Bind - PullRequest
       44

Async принять с Boost Bind

0 голосов
/ 28 декабря 2018

Я пытаюсь привязать обработчик async_accept к функции member .Перегрузка async_accept, которую я пытаюсь использовать:

template<typename MoveAcceptHandler>
DEDUCED async_accept(MoveAcceptHandler && handler);

Для обработчика async_accept требуется следующая подпись:

void handler(const boost::system::error_code& error,
   typename Protocol::socket peer);

Я пытаюсь bindк обработчику со следующим:

_acceptor.async_accept( boost::bind( &http_server::accepted, this, ph::_1, ph::_2 ) );

Мой член * Функция обработчика имеет следующую подпись:

void http_server::accepted( boost::system::error_code const& ec, boost::asio::ip::tcp::socket socket )

При компиляции я получаю следующую ошибку:

ошибка: нет соответствующей функции для вызова объекта типа 'boost :: _ mfi :: mf2>' unwrapper :: unwrap (f, 0) (a [base_type :: a1_], a[base_type :: a2_], a [base_type :: a3 _]);

Я не уверен, где моя ошибка.Конечно, я могу просто обойти проблему и использовать lambda, но мне любопытно, что я сделал неправильно.

РЕДАКТИРОВАТЬ:

http_server.hpp

class http_server
{
public:
    http_server( std::string_view host, std::string_view port );
    void listen( );
private:
    void start_accept( );
    void handle_accept( boost::system::error_code const& ec );
private:
    std::unique_ptr<boost::asio::io_context> _ctx;
    std::unique_ptr<boost::asio::io_context::work> _work;
    boost::asio::ip::tcp::acceptor _acceptor;
    boost::asio::ip::tcp::socket _socket;
    std::vector<connection> _connections;
};

http_server.cpp

using tcp = boost::asio::ip::tcp;

http_server::http_server( std::string_view host, std::string_view port):
 _ctx{ std::make_unique<boost::asio::io_context>( ) },
 _work{ std::make_unique<boost::asio::io_context::work>( *_ctx ) },
 _acceptor{ *_ctx },
 _socket{ *_ctx }
 {
     tcp::resolver resolver( *_ctx );
     tcp::endpoint endpoint =
        *resolver.resolve( host, port ).begin( );

     _acceptor.open( endpoint.protocol( ) );
     _acceptor.set_option( tcp::acceptor::reuse_address( true ) );
     _acceptor.bind( endpoint );
 }

void http_server::listen( )
 {
     uint32_t threads = std::thread::hardware_concurrency( );
     while( threads > 0 )
     { 
         _thread_pool.create_thread( [ this ]( )
         {
             while( true )
             {
                 try
                 {
                     _ctx->run( ); 
                     break;
                 }
                 catch( std::exception const& ex )
                 {
                     std::cerr << ex.what( ) << '\n';
                 }
             }                 
         } );
         --threads;                            
     }
     _acceptor.listen( boost::asio::socket_base::max_connections );
     start_accept( );
 }

void http_server::start_accept( )
 {
     namespace ph = std::placeholders;

     std::cout << "Waiting for connection\n";
     _acceptor.async_accept( _socket, boost::bind( &http_server::handle_accept, this, ph::_1 ) );
}


void http_server::handle_accept( boost::system::error_code const& ec )
{
    if( !_acceptor.is_open( ) ) return;
    if( !ec )
    {
        connection& con = _connections.emplace_back( connection{ std::move( _socket ) } );
        std::cout << "Number of connections: " << _connections.size( ) << '\n';
        con.handle_requests( );
    }
    start_accept( );
}

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Да, добавленный контекст объяснил, что ph был псевдонимом для std::paceholders:

 namespace ph = std::placeholders;

 std::cout << "Waiting for connection\n";
 _acceptor.async_accept( _socket, boost::bind( &http_server::handle_accept, this, ph::_1 ) );

Это не работает, если вы не используете std::bind или вы используете заполнители Boost Bind:

Live On Wandbox

_acceptor.async_accept( _socket, boost::bind( &http_server::handle_accept, this, ::_1 ) );
_acceptor.async_accept( _socket, boost::bind( &http_server::handle_accept, this, boost::asio::placeholders::error ) );
_acceptor.async_accept( _socket, std::bind( &http_server::handle_accept, this, std::placeholders::_1 ) );

По какой-то странной причине неудачиBoost объявляет свои заполнители в глобальном пространстве имен (!!!).Но Boost Lambda, Boost Phoenix, Boost Spirit и другие этого не делают.Никогда не смешивайте и не сопоставляйте местозаполнители, если они специально не предназначены для него.

Заполнители Boost Asio совместимы как с Boost Bind, но не с std :: bind

0 голосов
/ 28 декабря 2018

Таким образом, я смог исправить проблему, изменив эту строку:

_acceptor.async_accept( _socket, boost::bind( &http_server::handle_accept, this, ph::_1 ) );

На это:

_acceptor.async_accept( _socket, boost::bind( &http_server::handle_accept, this, boost::asio::placeholders::error ) );

Таким образом, вместо использования std::placeholders или boost::placeholders Мне пришлось специально использовать boost::asio::placeholders::error, чтобы функция правильно набрала bind.

...