Zwiększenie prędkości zapisu ASIO zawiesza się przy wyłączaniu urządzenia

0

Pytanie

Mam serwer aplikacji, która wykorzystuje boost ASIO do komunikacji z wieloma klientami. Serwer aplikacja działa na serwerze Linux, a klienci-na stołach roboczych Windows.

Aktualna konstrukcja многопоточна, choć jest tylko jeden boost ASIO thead (który działa boost::asio::io_context). Strumień boost ASIO odpowiada tylko za odczyt, zapis i niektóre rzadkie wysyłki. Odczyt odbywa się za pomocą boost::asio::async_read ale kopiuje otrzymaną wiadomość, aby inny wątek mógł wykonać pracę w zakresie obróbki. Pisanie odbywa się za pomocą boost::asio::write ale wiadomość już skopiowana i przekazana w strumień boost ASIO

W większości przypadków, gdy klient wyłącza, boost ASIO zgłasza błąd, wyłączam odpowiednie gniazdo, a inne gniazda nadal pracować. Jednak, jeśli na pulpicie systemu Windows klienta, awaria zasilania podczas boost::asio::write pisze do nich, boost nie wykryje problem i zawiesza się boost::asio::write. Czasami zawiesza się prawie na 20 minut i w tym czasie serwer nie może komunikować się z innymi klientami

Z tego co wyczytałem w Internecie, autorzy boost ASIO nie zamierzają wprowadzać ustawienie limitu czasu. Próbowałem ustawić wartość SO_SNDTIMEO równy 5 sekund, ale to w żaden sposób nie wpłynęło na zawiesza się wpisów. W tej chwili jestem najlepiej domyślam się, że aby rozwiązać ten problem, należy dostarczyć do każdego gniazda osobny wątek, aby jeden klient nie mógł wyłączyć innych klientów. Czy są jakieś lepsze opcje niż ten? Jeśli dam każdemu gniazda swój własny wątek, czy to oznacza, że będę potrzebował boost::asio::io_context dla każdego strumienia, aby uniknąć zawieszenia wpisów?

Zmiana: Po przejrzeniu komentarzy próbowałem powtórzyć funkcję, która powoduje boost::asio::write z boost::asio::async_write. Poniżej mam kod, który został uproszczony do SO, ale nadal pokazuje, jaka była całkowita zmiana:

Początkowo z 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();
    });
}

Przerobione z 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();
            }
        );
    });
}

Blokada została wprowadzona w drugim kodzie, aby zagwarantować tylko jedno połączenie boost::asio::async_write był aktywny w czasie (wiem, że są lepsze sposoby na to, ale to jest łatwiejsze dla testów). Oba te kody mają jeden i ten sam problem z zawieszaniem się komputera boost ASIO w przypadku awarii zasilania klienta. Jednak oni spędzają na różne sposoby, asynchroniczny kod na boost ASIO wykonywać inne czynności, po prostu nie nagrywa dalej, aż zawiesza się, nie doprowadzi do błędu

Podczas pojedynczego eksperymentu próbowałem zainstalować SO_KEEPALIVE ale to również nie rozwiązało problem z zawieszaniem się komputera

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

Najlepsza odpowiedź

1

Zgadzam się z komentatorami w tym, że właśnie tak zwykle działa TCP.

Należy pamiętać, że można wprowadzić limity czasu za pomocą zegara ASIO, który pozwala anulować synchroniczne operacje ze swoimi gniazdami.

Istnieje wiele przykładów, jeśli szukasz

  • boost::asio::steady_timer, oost::asio::high_resolution_timer i podobne członkowie rodziny godzin std::chrono
  • wzrost::deadline_timer
2021-11-22 22:29:35

W innych językach

Ta strona jest w innych językach

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