Повышение скорости записи ASIO зависает при отключении устройства

0

Вопрос

У меня есть серверное приложение, которое использует boost ASIO для связи с несколькими клиентами. Серверное приложение работает на сервере Linux, а клиенты-на рабочих столах Windows.

Текущая конструкция многопоточна, хотя есть только один boost ASIO thead (который работает boost::asio::io_context). Поток boost ASIO отвечает только за чтение, запись и некоторые нечастые отправки. Чтение выполняется с помощью boost::asio::async_read но копирует полученное сообщение, чтобы другой поток мог выполнить работу по обработке. Написание осуществляется с помощью boost::asio::write но сообщение уже скопировано и передано в поток boost ASIO

В большинстве случаев, когда клиент отключается, boost ASIO выдает ошибку, я отключаю соответствующий сокет, а другие сокеты продолжают работать. Однако, если на рабочем столе Windows клиента произошел сбой питания во время boost::asio::write пишет им, то boost не обнаруживает проблему и зависает в boost::asio::write. Иногда он зависает почти на 20 минут, и в течение этого времени сервер не может взаимодействовать с другими клиентами

Из того, что я прочитал в Интернете, авторы boost ASIO не намерены вводить параметр тайм-аута. Я попытался установить значение SO_SNDTIMEO равным 5 секундам, но это никак не повлияло на зависание записи. На данный момент я лучше всего предполагаю, что для решения этой проблемы нужно предоставить каждому сокету отдельный поток, чтобы один клиент не мог отключить других клиентов. Есть ли какие-то лучшие варианты, чем этот? Если я дам каждому сокету свой собственный поток, означает ли это, что мне понадобится boost::asio::io_context для каждого потока, чтобы избежать зависания записи?

Изменить: После просмотра комментариев я попытался повторить функцию, которая вызывает boost::asio::write с boost::asio::async_write. Ниже у меня есть код, который был упрощен для SO, но все еще показывает, каково было общее изменение:

Первоначально с boost::asio::write:

inline void MessagingServer::writeMessage(
    GuiSession* const  a_guiSession,
    const PB::Message& a_msg
) {
    boost::asio::dispatch(m_guiIoIoContext, [this, a_guiSession, a_msg]() {
        // I removed code that writes a_msg's bytes into m_guiIoWriteBuf
        // and sets totalSize to simplify for SO

        boost::system::error_code error;
        boost::asio::write(a_guiSession->m_guiIoGsSocket, boost::asio::buffer(m_guiIoWriteBuf, totalSize), error);
        if (UNLIKELY(error))
            ERRLOG << a_guiSession->m_gsSessionId << " write failed: " << error.message();
    });
}

Переделано с boost::asio::async_write:

inline void MessagingServer::writeMessage(
    GuiSession* const  a_guiSession,
    const PB::Message& a_msg
) {
    a_guiSession->m_tempMutex.lock();

    boost::asio::dispatch(m_guiIoIoContext, [this, a_guiSession, a_msg]() {
        // I removed code that writes a_msg's bytes into m_guiIoWriteBuf
        // and sets totalSize to simplify for SO

        boost::asio::async_write(
            a_guiSession->m_guiIoGsSocket,
            boost::asio::buffer(m_guiIoWriteBuf, totalSize),
            [this, a_guiSession](const boost::system::error_code& a_error, std::size_t) {
                if (UNLIKELY(a_error))
                    ERRLOG << a_guiSession->m_gsSessionId << " write failed: " << a_error.message();

                a_guiSession->m_tempMutex.unlock();
            }
        );
    });
}

Блокировка была введена во втором коде, чтобы гарантировать только один вызов boost::asio::async_write был активен в то время (я знаю, что есть более эффективные способы сделать это, но это проще для тестирования). Оба этих кода имеют одну и ту же проблему зависания boost ASIO при сбое питания клиента. Однако они зависают по-разному, асинхронный код позволяет boost ASIO выполнять другие действия, просто не записывает дальше, пока зависание не приведет к ошибке

Во время отдельного эксперимента я попытался установить SO_KEEPALIVE но это также не решило проблему зависания

asio boost c++ multithreading
2021-11-22 19:46:12
1

Лучший ответ

1

Я согласен с комментаторами в том, что именно так обычно работает TCP.

Обратите внимание, что вы можете ввести тайм-ауты с помощью таймера ASIO, который позволяет отменять синхронные операции с вашими сокетами.

Есть много много примеров, если вы ищете

  • boost::asio::steady_timer, oost::asio::high_resolution_timer и аналогичные члены семейства часов std::chrono
  • повышение::deadline_timer
2021-11-22 22:29:35

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................