Boost ASIO async акцептор не отваря порт за слушане

ОС: linux 64 бита ARCH.

BOOST : 1.46.1

КОМПИЛАТОР: clang++ / GCC.

Имам фрагмент от код, който има свързване на tcp акцептор, моделиран на пример за boost::asio (Сървър за чат). Въпреки това, когато стартирам фрагмента, No listening TCP socket се показва в netstat listening(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();
}    

person Hassan Syed    schedule 12.07.2011    source източник


Отговори (2)


Открих, че мога да накарам това да работи на моята машина с Windows, ако променя endpoint и acceptor на споделени указатели и вместо да ги създавам, като ги предавам като аргументи в конструктора, специално създадох споделените указатели вътре в конструктора. Не съм съвсем сигурен защо това работи. Единственото ми предположение е, че може би няма гаранции, че аргументите на конструктора се предават или създават в реда, в който се появяват, и по този начин можете да опитате да създадете acceptor с endpoint, което все още не е правилно инициализирано? Това наистина е единственото ми предположение. Кажете ми дали това работи за вас. Успях да се свържа успешно чрез localhost на порт 5000.

Без тези промени клиентът, с който се опитах да се свържа чрез 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 вече са създадени. Промяната на дефиницията на класа, така че членът m_port да е деклариран преди endpoint и acceptor, коригира проблема.

person aardvarkk    schedule 12.07.2011
comment
уау, това реши проблема, благодаря. Вероятно има нещо общо с реда на инициализация в списъка за инициализация. Мислех, че е отгоре надолу. - person Hassan Syed; 12.07.2011
comment
stackoverflow.com/questions/4037219 /. Отговорът на потребителя in silico, Моите предположения, при които този списък на инициализаторите определя реда на оценката. Но редът на деклариране определя реда. Все пак трябва да го пробвам. - person Hassan Syed; 12.07.2011
comment
Тогава това отговаря ли на въпроса ви или имаше нещо друго? - person aardvarkk; 12.07.2011
comment
Да, така е, но все пак е странно, че работи за други :D - person Hassan Syed; 12.07.2011
comment
Да -- току-що прочетох този отговор и вашият пример с код също има декларациите в правилния ред, така че не съм сигурен какъв точно може да е проблемът... - person aardvarkk; 12.07.2011
comment
@Hassan Syed Открих проблема. Ще редактирам оригиналния отговор, за да го добавя. - person aardvarkk; 12.07.2011

Получих грешка при компилирането на вашия код

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; }

to

io_service & get_io_service() { return m_io_service; }

изглежда разрешава грешката на компилатора. Изпълнението на получения двоичен файл показва гнездо за слушане в netstat -l -t за мен.

person Sam Miller    schedule 12.07.2011