异步接受与提升绑定

Async accept with boost bind

我正在尝试将 async_accept 的处理程序绑定到 成员 函数。 我尝试使用的 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 ) );

我的 member 处理程序函数具有以下签名:

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

编译时出现以下错误:

error: no matching function for call to object of type '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( );
}

所以我能够通过更改此行来更正问题:

_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 ) );

因此,我不得不专门使用 boost::asio::placeholders::error 而不是使用 std::placeholdersboost::placeholders 以使函数正确地 bind

是的,添加的上下文解释说 phstd::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