【问题标题】:Boost ASIO async acceptor not opening a listening portBoost ASIO 异步接受器未打开侦听端口
【发布时间】:2011-10-03 15:55:56
【问题描述】:

操作系统:linux 64 位 ARCH。

提升:1.46.1

编译器:clang++ / GCC。

我有一个代码片段,它连接了一个以 boost::asio 示例 (Chat Server) 为模型的 tcp 接受器。但是,当我运行该片段时,没有侦听 TCP 套接字出现在 netstat listener(linux) 中。但是,聊天服务器示例在编译后会显示出来。有人可以指出我做错了什么吗?

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <list>
#include <iostream>


using namespace boost::asio;
  using namespace boost::asio::ip;

  class ClientConnection
  {
  public:
    ClientConnection(io_service & io_s)
      : m_socket(io_s) {}
    tcp::socket & socket() { return m_socket; }
  private:
    tcp::socket m_socket;  
  };

  typedef boost::shared_ptr<ClientConnection> client_connection_ptr;

  class ClientConnectionAcceptor
  {
  public:
    ClientConnectionAcceptor(unsigned short port)
      : m_io_service(),
        m_port(port),
        m_endpoint(tcp::v4(), m_port),
        m_acceptor(m_io_service, m_endpoint)
    {
      std::cout << "acceptor is open : " << m_acceptor.is_open() << std::endl;
      client_connection_ptr ccp(new ClientConnection(m_io_service));

      m_acceptor.async_accept(  
        ccp->socket(),
        boost::bind(&ClientConnectionAcceptor::handle_accept,this, 
        ccp, placeholders::error));
    } 

    void handle_accept(client_connection_ptr ccp, const boost::system::error_code & error)
    {
      std::cout << "in handle_accept" << std::endl;  
      if(!error)
      {
       // m_rpc_oracle.AddNewClient(ccp);
        client_connection_ptr new_ccp(new ClientConnection(m_io_service));
        m_acceptor.async_accept(  
          new_ccp->socket(),
          boost::bind(&ClientConnectionAcceptor::handle_accept,this, 
          ccp, placeholders::error));

      }
    }

    io_service & io_service() { return m_io_service; }
  private:
    boost::asio::io_service m_io_service;
    tcp::endpoint m_endpoint;
    tcp::acceptor m_acceptor;
    unsigned short m_port;
  };


int main()
{
  ClientConnectionAcceptor acceptor(5000);
  acceptor.io_service().run();
}    

【问题讨论】:

    标签: c++ network-programming tcp boost-asio


    【解决方案1】:

    我发现如果我将endpoint 和acceptor 更改为共享指针,而不是通过将它们作为参数传递到构造函数中来创建它们,我可以在我的Windows 机器上运行它,而是专门创建了共享指针构造函数内部的指针。我不确定为什么会这样。我唯一的猜测是,也许无法保证构造函数参数按照它们出现的顺序传递或创建,因此您可以尝试使用尚未正确初始化的endpoint 创建acceptor?这真的是我唯一的猜测。让我知道这是否适合您。我可以通过端口5000 上的localhost 成功连接。

    如果没有这些更改,我尝试通过localhost 连接的客户端告诉我连接被主动拒绝。然而,这种安排是成功的,并且似乎尽可能少地偏离您的原始代码。希望对您有所帮助。

    #include <boost/asio.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/bind.hpp>
    #include <list>
    #include <iostream>
    
    using namespace boost::asio;
    using namespace boost::asio::ip;
    
    class ClientConnection
    {
    public:
      ClientConnection(io_service & io_s)
        : m_socket(io_s) {}
      tcp::socket & socket() { return m_socket; }
    private:
      tcp::socket m_socket;  
    };
    
    typedef boost::shared_ptr<ClientConnection> client_connection_ptr;
    
    class ClientConnectionAcceptor
    {
    public:
      ClientConnectionAcceptor(unsigned short port)
        : m_io_service(),
        m_port(port)
      {
        // now initializing endpoint and acceptor as shared pointers inside the constructor
        m_endpoint = boost::shared_ptr<tcp::endpoint>(new tcp::endpoint(tcp::v4(), m_port));
        m_acceptor = boost::shared_ptr<tcp::acceptor>(new tcp::acceptor(m_io_service, *m_endpoint));
    
        std::cout << "acceptor is open : " << m_acceptor->is_open() << std::endl;
        client_connection_ptr ccp(new ClientConnection(m_io_service));
    
        m_acceptor->async_accept(  
          ccp->socket(),
          boost::bind(&ClientConnectionAcceptor::handle_accept,this, 
          ccp, placeholders::error));
      } 
    
      void handle_accept(client_connection_ptr ccp, const boost::system::error_code & error)
      {
        std::cout << "in handle_accept" << std::endl;  
        if(!error)
        {
          // m_rpc_oracle.AddNewClient(ccp);
          client_connection_ptr new_ccp(new ClientConnection(m_io_service));
          m_acceptor->async_accept(  
            new_ccp->socket(),
            boost::bind(&ClientConnectionAcceptor::handle_accept,this, 
            ccp, placeholders::error));
    
        }
      }
    
      io_service & io_service() { return m_io_service; }
    private:
      boost::asio::io_service m_io_service;
      boost::shared_ptr<tcp::endpoint> m_endpoint;
      boost::shared_ptr<tcp::acceptor> m_acceptor;
      unsigned short m_port;
    };
    
    
    int main()
    {
      ClientConnectionAcceptor acceptor(5000);
      acceptor.io_service().run();
    }    
    

    编辑

    经过进一步调查,发现问题实际上与ClientConnectionAcceptor类的初始化列表有关。在类定义中,成员 m_port 被声明 m_endpoint 和 m_acceptor。结果,即使初始化列表似乎设置了端口号之前 endpoint 和acceptor 被创建,事实上,端口值是无效的或初始化直到之后 endpoint 和 acceptor 已经创建。更改类定义以在 endpoint 和 acceptor 之前声明成员 m_port 可以解决问题。

    【讨论】:

    • 哇,这确实解决了问题,谢谢。它可能与初始化列表中的初始化顺序有关。我以为是自上而下的。
    • stackoverflow.com/questions/4037219/…。用户“in silico”的响应,我的假设是初始化列表顺序决定了评估顺序。但是决定顺序的是声明的顺序。不过我还是得试试看。
    • 这是否回答了您的问题,还是有其他问题?
    • 是的,但它仍然适用于其他人仍然很奇怪:D
    • 是的——我刚刚阅读了那个答案,你的代码示例确实也有正确顺序的声明,所以我不确定问题到底是什么......
    【解决方案2】:

    编译你的代码时出错

    async_accept.cc:56: error: declaration of ‘boost::asio::io_service& ClientConnectionAcceptor::io_service()’
    /opt/local/include/boost/asio/io_service.hpp:186: error: changes meaning of ‘io_service’ from ‘class boost::asio::io_service’
    

    变化

    io_service & io_service() { return m_io_service; }
    

    到

    io_service & get_io_service() { return m_io_service; }
    

    似乎解决了编译器故障。运行生成的二进制文件会在netstat -l -t 中为我显示一个监听套接字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多