Как делают я чисто повторно подключаю повышение:: сокет после разъединения?

Мое клиентское приложение использует a boost::asio::ip::tcp::socket соединяться с удаленным сервером. Если бы приложение теряет соединение с этим сервером (например, из-за катастрофического отказа сервера или быть завершением работы), я хотел бы, чтобы это делало попытку повторно подключения равномерно, пока это не успешно выполняется.

То, что я должен сделать на клиентском, чтобы чисто обработать разъединение, убраться и затем неоднократно пытаться, снова соединяется?

В настоящее время интересные биты моего кода выглядят примерно так.

Я connect как это:

bool MyClient::myconnect()
{
    bool isConnected = false;

    // Attempt connection
    socket.connect(server_endpoint, errorcode);

    if (errorcode)
    {
        cerr << "Connection failed: " << errorcode.message() << endl;
        mydisconnect();
    }
    else
    {
        isConnected = true;

        // Connected so setup async read for an incoming message.
        startReadMessage();

        // And start the io_service_thread
        io_service_thread = new boost::thread(
            boost::bind(&MyClient::runIOService, this, boost::ref(io_service)));
    }
    return (isConnected)
}

Где runIOServer() метод справедлив:

void MyClient::runIOService(boost::asio::io_service& io_service)
{
    size_t executedCount = io_service.run();
    cout << "io_service: " << executedCount << " handlers executed." << endl;
    io_service.reset();
}

И если какой-либо из асинхронных обработчиков чтений возвращает ошибку затем, они просто называют это disconnect метод:

void MyClient::mydisconnect(void)
{
    boost::system::error_code errorcode;

    if (socket.is_open())
    {
        // Boost documentation recommends calling shutdown first
        // for "graceful" closing of socket.
        socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
        if (errorcode)
        {
            cerr << "socket.shutdown error: " << errorcode.message() << endl;
        }

        socket.close(errorcode);
        if (errorcode)
        {
            cerr << "socket.close error: " << errorcode.message() << endl;
        }    

        // Notify the observer we have disconnected
        myObserver->disconnected();            
    }

.. который пытается корректно разъединиться и затем уведомляет наблюдателя, который начнет звонить connect() в пятисекундных интервалах, пока это не подключено повторно.

Есть ли что-либо еще, что я должен сделать?

В настоящее время это, действительно кажется, работает. Если я уничтожаю сервер, с которым это подключено к, мне получаю ожидаемый "End of file" ошибка в моих обработчиках чтений и mydisconnect() назван без любых проблем.

Но когда это затем пытается снова соединиться и сбои, я вижу, что он сообщает "socket.shutdown error: Invalid argument". Это просто, потому что я пытаюсь завершить работу сокета, который не имеет никакого чтения-записей, ожидающего на нем? Или это - что-то больше?

27
задан GrahamS 17 June 2010 в 14:55
поделиться

3 ответа

Вам необходимо создавать новый boost :: asio :: ip :: tcp :: socket каждый раз при повторном подключении. Самый простой способ сделать это, вероятно, просто выделить сокет в куче, используя boost :: shared_ptr (вы, вероятно, также можете обойтись с scoped_ptr , если ваш сокет полностью инкапсулирован внутри класс). Например:

bool MyClient::myconnect()
{
    bool isConnected = false;

    // Attempt connection
    // socket is of type boost::shared_ptr<boost::asio::ip::tcp::socket>
    socket.reset(new boost::asio::ip::tcp::socket(...));
    socket->connect(server_endpoint, errorcode);
    // ...
}

Затем, когда вызывается mydisconnect , вы можете освободить сокет:

void MyClient::mydisconnect(void)
{
    // ...
    // deallocate socket.  will close any open descriptors
    socket.reset();
}

Ошибка, которую вы видите, вероятно, является результатом очистки ОС файлового дескриптора после того, как вы вызвали закрыть . Когда вы вызываете close , а затем пытаетесь подключить к тому же сокету, вы, вероятно, пытаетесь подключить недопустимый файловый дескриптор. На этом этапе вы должны увидеть сообщение об ошибке, начинающееся с «Ошибка подключения: ...» в соответствии с вашей логикой, но затем вы вызываете mydisconnect , который, вероятно, затем пытается вызвать shutdown на недопустимый дескриптор файла. Порочный круг!

27
ответ дан 28 November 2019 в 05:30
поделиться

В прошлом я делал нечто подобное, используя Boost.Asio. Я использую асинхронные методы, поэтому переподключение обычно заключается в том, чтобы вывести существующий объект ip::tcp::socket из области видимости, а затем создать новый для вызова async_connect. Если async_connect не удается, я использую таймер, чтобы немного поспать, а затем повторить попытку.

2
ответ дан 28 November 2019 в 05:30
поделиться

Для ясности вот окончательный подход, который я использовал (но он основан на ответе bjlaub'а, поэтому, пожалуйста, отдайте все голоса ему):

Я объявил член socket как scoped_ptr:

boost::scoped_ptr<boost::asio::ip::tcp::socket> socket;

Затем я модифицировал свой метод connect так:

bool MyClient::myconnect()
{
    bool isConnected = false;

    // Create new socket (old one is destroyed automatically)
    socket.reset(new boost::asio::ip::tcp::socket(io_service));

    // Attempt connection
    socket->connect(server_endpoint, errorcode);

    if (errorcode)
    {
        cerr << "Connection failed: " << errorcode.message() << endl;
        socket->close();
    }
    else
    {
        isConnected = true;

        // Connected so setup async read for an incoming message.
        startReadMessage();

        // And start the io_service_thread
        io_service_thread = new boost::thread(
            boost::bind(&MyClient::runIOService, this, boost::ref(io_service)));
    }
    return (isConnected)
}

Примечание: этот вопрос был первоначально задан и отвечен еще в 2010 году, но если вы сейчас используете C++11 или более поздние версии, то std::unique_ptr обычно будет лучшим выбором, чем boost::scoped_ptr

8
ответ дан 28 November 2019 в 05:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: