La spinta ASIO scrivere bloccarsi quando il dispositivo si disconnette

0

Domanda

Ho una applicazione server che utilizza la spinta ASIO per comunicare con i diversi clienti. L'applicazione server gira su un server Linux e client eseguire sul desktop di Windows.

Il design attuale è multi-threaded anche se c'è solo una spinta ASIO thead (che corre boost::asio::io_context). La spinta ASIO thread è responsabile solo per la lettura, la scrittura, e alcuni rari spedizione. La lettura viene fatta utilizzando boost::asio::async_read ma copia il messaggio risultante in modo che un altro thread può fare il lavoro di elaborazione. La scrittura è fatta utilizzando boost::asio::write ma il messaggio è già stato copiato e ceduto alla spinta ASIO thread

Nella maggior parte dei casi quando un client si disconnette la spinta ASIO genera un errore, chiudo il socket associato, e le altre prese di continuare a lavorare. Tuttavia, se un client desktop di Windows è un'interruzione dell'alimentazione durante boost::asio::write la scrittura, quindi, boost non rileva un problema e che si blocca in boost::asio::write. Si blocca per quasi 20 minuti e a volte il server non è in grado di comunicare con gli altri clienti durante questo periodo di tempo

Da quello che ho letto online gli autori di spinta ASIO non hanno alcuna intenzione di introdurre un parametro di timeout. Ho provato impostazione SO_SNDTIMEO per 5 secondi, ma che non hanno alcun effetto sulla scrittura appendere. Ora come ora la mia ipotesi migliore per risolvere il problema è quello di dare ad ogni presa un thread diverso, in modo che un client non può prendere gli altri clienti. Ci sono opzioni migliori di questo? Se mi faccio dare ogni presa proprio thread vuol dire che ho bisogno di un boost::asio::io_context per thread per evitare la cancellazione del blocco?

Edit: Dopo aver visto i commenti che ho provato a rifare la funzione che chiama boost::asio::write con boost::asio::async_write. Sotto ho un po ' di codice che è stato semplificato per COSÌ tanto, ma mostra ancora che la variazione complessiva è stata:

Originariamente con 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();
    });
}

Rifatto con 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();
            }
        );
    });
}

Il blocco è stato introdotto nel secondo codice di garantire solo una chiamata a boost::asio::async_write fu attivo alla volta (sono consapevole che ci sono più performanti modi per fare questo, ma questo è più semplice per il test). Entrambi questi codici hanno lo stesso problema di appendere la spinta ASIO quando il client ha un guasto di alimentazione. Tuttavia essi appendere in modi diversi, il codice asincrono non consente, per la spinta ASIO per eseguire altre azioni, solo che non scrive ancora fino pensile produce un errore

Durante un esperimento separato l'ho fatto provare a impostare SO_KEEPALIVE ma che anche non risolvere il blocco problema

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

Migliore risposta

1

Sono d'accordo con i commentatori che questo è come TCP generalmente funziona.

Si noti che è possibile introdurre timeout durante l'utilizzo di un ASIO timer che consente di annullare aynchronous operazioni sul socket.

Ci sono molti esempi, se si cerca

  • boost::asio::steady_timer, oost::asio::high_resolution_timer e analoga membri della std::chrono famiglia di orologi
  • boost::deadline_timer
2021-11-22 22:29:35

In altre lingue

Questa pagina è in altre lingue

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