带有加速绑定的异步接受

时间:2018-12-27 23:47:42

标签: c++ boost boost-asio

我正在尝试将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 :(得分:1)

是的,添加的上下文说明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不兼容

答案 1 :(得分:0)

因此我可以通过更改以下行来纠正此问题:

_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::placeholdersboost::asio::placeholders::error才能使函数正确地bind