代码之家  ›  专栏  ›  技术社区  ›  user8922003

C++boost::boost的accept处理程序中的asio可变模板运算符::asio::basic\u socket\u acceptor::async\u accept()

  •  2
  • user8922003  · 技术社区  · 7 年前

    我正在尝试创建一个接受连接的异步tcp服务器。我将使用如下所示的accept handler函数对象:

    template <typename Function>
    struct callback
    {
       Function func_;
    
       callback()
       {
       }
    
       callback(Function&& f)
            : func_(std::forward<Function>(f))
       {
       }
    
       template <typename ...Args>
       void operator() (Args&& ...args)
       {
             func_(std::forward<Args>(args)...);
       }
    };
    

    我的服务器类:

    #include <boost/bind.hpp>
    #include <boost/asio.hpp>
    
    #include <session.hpp>
    #include <handler.hpp>
    class server
    {
    private:
        typedef callback<boost::function<void(const boost::system::error_code&, session_ptr&)>> accept_handler;
    
        boost::asio::io_service& io_service_;
        tcp::acceptor acceptor_;
        accept_handler handler_;
    
    public:
        server(boost::asio::io_service& io_service, short port)
            : io_service_(io_service),
              acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
        {
            session_ptr new_session = session_ptr(new session(io_service_));
            auto callback =  boost::bind(&server::handle_accept,
                                         this,
                                         boost::asio::placeholders::error,
                                         new_session);
    
            handler_ = accept_handler(std::move(callback));
    
    
            acceptor_.async_accept(new_session->socket(),
                                   handler_);
        }
    
        void handle_accept(const boost::system::error_code& error, session_ptr new_session)
        {
            if (!error)
            {
                new_session->start();
                new_session.reset(new session(io_service_));
    
                acceptor_.async_accept(new_session->socket(),
                                       handler_);
    
            }
        }
    };
    

    但是,当我尝试编译时,会出现以下错误:

    错误:调用不匹配(boost::function&)>)(const boost::system::error\u code&) func_(std::转发(args)…);

    所以我必须只使用满足AcceptHandler要求的处理程序

    struct accept_handler
    {
      ...
      void operator()(
          const boost::system::error_code& ec)
      {
        ...
      }
      ...
    };
    

    或者有一种解决方案可以使用重载的可变模板opreator()?

    1 回复  |  直到 7 年前
        1
  •  0
  •   sehe    7 年前

    在意识到真正的错误之后 :

    好消息是:只需更改一行即可修复错误:

    typedef callback<boost::function<void(const boost::system::error_code&, session_ptr&)>> accept_handler;
    

    进入

    typedef callback<boost::function<void(const boost::system::error_code&)>> accept_handler;
    

    出于各种原因,之前的定义完全错误:

    • 它不符合处理程序的要求
    • 它也不符合 bind 表达式: bind(&server::handle_accept, this, asio::placeholders::error, new_session) . 注意,它只有一个占位符( asio::placeholders::error )所以它不可能在两个参数下工作

    Live On Coliru

    #include <boost/function.hpp>
    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    
    namespace ba = boost::asio;
    using ba::ip::tcp;
    
    struct session : std::enable_shared_from_this<session> {
        session(ba::io_service& svc) : _socket(svc) {}
    
        void start() {} // do something asynchronously
        tcp::socket& socket() { return _socket; }
    
        tcp::socket _socket;
    };
    
    using session_ptr = std::shared_ptr<session>;
    
    template <typename Function>
    struct callback
    {
       Function func_;
    
       callback(Function&& f = {}) : func_(std::forward<Function>(f)) {
       }
    
       template <typename ...Args>
       void operator() (Args&& ...args) {
           func_(std::forward<Args>(args)...);
       }
    };
    
    class server
    {
    private:
        typedef callback<boost::function<void(const boost::system::error_code&)>> accept_handler;
    
        ba::io_service& io_service_;
        tcp::acceptor acceptor_;
        accept_handler handler_;
    
    public:
        server(ba::io_service& io_service, short port)
            : io_service_(io_service),
              acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
        {
            session_ptr new_session = session_ptr(new session(io_service_));
            handler_ = accept_handler(bind(&server::handle_accept, this, ba::placeholders::error, new_session));
    
            acceptor_.async_accept(new_session->socket(), handler_);
        }
    
        void handle_accept(const boost::system::error_code& error, session_ptr new_session)
        {
            if (!error)
            {
                new_session->start();
                new_session.reset(new session(io_service_));
    
                acceptor_.async_accept(new_session->socket(),
                                       handler_);
    
            }
        }
    };
    
    int main() {
    }
    

    简化:删除冗余包装

    callback<> , accept_handler 有任何用途:

    Live On Coliru

    class server
    {
    private:
        ba::io_service& io_service_;
        tcp::acceptor acceptor_;
    
    public:
        server(ba::io_service& io_service, short port)
            : io_service_(io_service),
              acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
        { 
            do_accept();
        }
    
        void do_accept() {
            session_ptr new_session = session_ptr(new session(io_service_));
            acceptor_.async_accept(new_session->socket(), bind(&server::handle_accept, this, ba::placeholders::error, new_session));
        }
    
        void handle_accept(const boost::system::error_code& error, session_ptr new_session)
        {
            if (!error) {
                new_session->start();
                do_accept();
            }
        }
    };
    

    更简单的方法:捕获Lambda

    您可以不使用绑定、占位符和 handle_accept 所有成员同时:

    Live On Coliru

    class server
    {
    private:
        ba::io_service& io_service_;
        tcp::acceptor acceptor_;
    
    public:
        server(ba::io_service& io_service, short port)
            : io_service_(io_service),
              acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
        { 
            do_accept();
        }
    
        void do_accept() {
            session_ptr new_session = std::make_shared<session>(io_service_);
    
            acceptor_.async_accept(new_session->socket(), [this,new_session](const boost::system::error_code& error) {
                if (!error) {
                    new_session->start();
                    do_accept();
                }
            });
        }
    };
    

    旧答案

    在第一次阅读中,我假设您遇到了一个我在Boost Asio和多态Lambda中经常遇到的经典陷阱。很抱歉

    事实上,在可变情况下,概念检查无法验证处理器要求。我在这里的方法是禁用需求检查:

    #define BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS 1
    

    如果存在不匹配,则丢失的主要信息是更友好的错误消息:

    • 当完成处理程序不满足必要的类型要求时,添加了更友好的编译器错误。当C++0x可用时(当前支持g++4.5或更高版本,以及MSVC 10),静态_断言也用于生成信息性错误消息。可以通过定义BOOST\u ASIO\u DISABLE\u HANDLER\u TYPE\u要求来禁用此检查。

    看见 http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/history.html