Acceptor и проблемы с Async_Accept - PullRequest
2 голосов
/ 10 июня 2010

См. Код.: P Я могу получить новые подключения до вызова async_accept ().Моя функция делегата также никогда не вызывается, поэтому я не могу управлять полученными подключениями, делая новые подключения бесполезными.;)

Так вот мой вопрос.Есть ли способ запретить акцептору Boost ASIO получать новые соединения самостоятельно и получать соединения только от async_accept ()?

Спасибо!

AlexSocket::AlexSocket(boost::asio::io_service& s): myService(s)
{
    //none at the moment
    connected = false;
    listening = false;

    using boost::asio::ip::tcp;
    mySocket = new tcp::socket(myService);
}

AlexSocket::~AlexSocket()
{
    delete mySocket;
}

bool AlexSocket::StartListening(int port)
{
    bool didStart = false;

    if (!this->listening)
    {
        //try to listen
        acceptor = new tcp::acceptor(this->myService);
        boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
        acceptor->open(endpoint.protocol());
        acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor->bind(endpoint);
        //CAN GET NEW CONNECTIONS HERE (before async_accept is called)
        acceptor->listen();

        didStart = true; //probably change?
        tcp::socket* tempNewSocket = new tcp::socket(this->myService);
        //acceptor->async_accept(*tempNewSocket, boost::bind(&AlexSocket::NewConnection, this, tempNewSocket, boost::asio::placeholders::error) );
    }
    else //already started!
        return false;

    this->listening = didStart;
    return didStart;
}

//this function is never called :(
void AlexSocket::NewConnection(tcp::socket* s, const boost::system::error_code& error)
{
    cout << "New Connection Made" << endl;
    //Start new accept async
    tcp::socket* tempNewSocket = new tcp::socket(this->myService);
    acceptor->async_accept(*tempNewSocket, boost::bind(&AlexSocket::NewConnection, this, tempNewSocket, boost::asio::placeholders::error) );
}

bool AlexSocket::ConnectToServer(std::string toConnectTo, string port)
{
    if (connected)
        return false;

    this->serverConnectedTo = toConnectTo;
    this->serverPort = port;

    ip::tcp::resolver resolver(myService);
    ip::tcp::resolver::query newQuery(toConnectTo, port);
    ip::tcp::resolver::iterator myIter = resolver.resolve(newQuery);
    ip::tcp::resolver::iterator end;

    //error
    boost::system::error_code error = boost::asio::error::host_not_found;

    //try each endpoint
    bool connected = false;
    while (error && myIter != end)
    {
        ip::tcp::endpoint endpoint = *myIter++;
        std::cout << endpoint << std::endl;

        mySocket->close();
        mySocket->connect(*myIter, error);

        if (error)
        {
            //try to connect, if it didn't work return false
            cout << "Did not Connect" << endl << error << endl;
        }
        else
        {
            //was able to connect
            cout << "Connected!" << endl;
            connected = true;
        }
        myIter++;
    }   
    this->connected = connected;
    return connected;
}

РЕДАКТИРОВАТЬ: Я изменил свой код, чтобы отразить то, что уже сказано в ответах.Я передаю в io_service к центру моего класса.Как вы можете видеть ниже, main НЕ вызывает run на сервисе, поэтому я могу предположить, что ничто не может быть в состоянии подключиться правильно?

Я поместил свой отладчик в строку listen () и перешел к «canyouseeme».org».Наберите 57422 и нажмите «Подключиться».Не удалось.Запустил строку listen ().Был в состоянии подключиться.Это не должно быть возможно, верно?Как никогда?: (

Понятия не имею, что делать дальше. Main () ниже.

int main()
{
    boost::asio::io_service s;
    AlexSocket test(s);

    test.StartListening(57422);

    test.ConnectToServer("localhost", "57422");

    cout << "Enter something to quit" << endl;
    int a2;
    cin >> a2;

    return 0;
}

Ответы [ 3 ]

3 голосов
/ 10 июня 2010

Так вот мой вопрос. Есть ли способ запретить акцептору Boost ASIO получать новые соединения самостоятельно и получать соединения только от async_accept ()?

Почему вы думаете, что это происходит? Если вы разместите полный код, это очень поможет. Когда я беру ваш фрагмент и помещаю шаблонную строку main и io_service :: run () вокруг нее, все работает нормально.

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include <iostream>

using namespace boost::asio;

class Socket {
public:
    Socket(
            io_service& io_service
          ) :
        _io_service( io_service ),
        _acceptor( new ip::tcp::acceptor(io_service) )
    {

    }

    bool start(int port)
    {
        //try to listen
        ip::tcp::endpoint endpoint(ip::tcp::v4(), port);
        _acceptor->open(endpoint.protocol());
        _acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
        _acceptor->bind(endpoint);
        //CAN GET NEW CONNECTIONS HERE (before async_accept is called)
        _acceptor->listen();

        ip::tcp::socket* temp = new ip::tcp::socket( _io_service );
        _acceptor->async_accept(
                *temp,
                boost::bind(
                    &Socket::NewConnection,
                    this,
                    temp,
                    boost::asio::placeholders::error
                    )
                );
    }

    void NewConnection(
            ip::tcp::socket* s, 
            const boost::system::error_code& error
            )
    {
        std::cout << "New Connection Made" << std::endl;
        //Start new accept async
        ip::tcp::socket* temp = new ip::tcp::socket( _io_service );
        _acceptor->async_accept(
                *temp,
                boost::bind(
                    &Socket::NewConnection, 
                    this,
                    temp,
                    boost::asio::placeholders::error
                    )
                );
    }
private:
    io_service& _io_service;
    ip::tcp::acceptor* _acceptor;
};

int
main()
{
    io_service foo;
    Socket sock( foo );
    sock.start(1234);
    foo.run();

    return 0;
}

скомпилируйте и запустите:

macmini:~ samm$ g++ -lboost_system accept.cc
macmini:~ samm$ ./a.out 
New Connection Made

телнет с другого терминала

macmini:~ samm$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
2 голосов
/ 05 июня 2012

Я думаю, что вы смешиваете здесь разные вещи.

С одной стороны, вы создаете сокет для обмена данными.Сокет - это не что иное, как конечная точка межпроцессного взаимодействия в компьютерной сети.Ваш boost :: asio :: tcp :: socket использует TCP-protocoll для связи;но в целом сокет может использовать другие протоколы.Для открытия tcp-сокета обычно используется последовательность open-bind-listen-accept на хосте.

С другой стороны, вы анализируете (базовое) TCP-соединение.

Итак, здесь есть две разные вещи.В то время как для сокета соединение считается «установленным» только после «принятия» хоста, базовое TCP-соединение уже установлено после того, как клиент подключается к прослушивающему сокету.(Со стороны сервера это соединение помещается в стек, из которого оно удаляется при вызове accept ()).

Так что единственный способ запретить соединение в вашем случае - это , а не для вызова listen ().

1 голос
/ 10 июня 2010

Если вы действительно получаете новое соединение в тот момент, когда вы звоните acceptor->listen(), то я озадачен этим. Что вы используете, чтобы определить, получили ли вы соединение или нет? Io_service, как правило, довольно «реактивен» в том смысле, что он реагирует только на события, на которые ему явно было дано указание реагировать.

В приведенном выше примере единственное, что я вижу, что могло бы инициировать "новое соединение", это вызов async_accept. Кроме того, то, что вы описали, не имеет смысла с точки зрения низкоуровневых сокетов (при использовании сокетов BSD обычно вы должны вызывать bind, listen и accept в таком порядке, и только тогда можно установить новое соединение) .

Я подозреваю, что у вас где-то есть какая-то неверная логика. Кто звонит StartListening и как часто он вызывается (его нужно вызывать только один раз). Вы проделали кучу дополнительных усилий по настройке объекта acceptor, который обычно не требуется в Asio - вы можете просто использовать конструктор acceptor для создания акцептора со всеми необходимыми параметрами, а затем просто вызвать async_accept * * 1014

acceptor = new tcp::acceptor(
    this->myService,
    boost::asio::ip::tcp::endpoint(
        boost::asio::ip::tcp::v4(),
        port),
    true);

tcp::socket* tempNewSocket = new tcp::socket(this->myService);
acceptor->async_accept(
    *tempNewSocket, 
    boost::bind(
        &AlexSocket::NewConnection, 
        this, 
        tempNewSocket, 
        boost::asio::placeholders::error) );
...