Maison >développement back-end >C++ >Comment empêcher les appels « async_write » entrelacés dans Boost Asio ?

Comment empêcher les appels « async_write » entrelacés dans Boost Asio ?

Linda Hamilton
Linda Hamiltonoriginal
2024-11-28 01:55:10916parcourir

How to Prevent Interleaved `async_write` Calls in Boost Asio?

Comment empêcher l'entrelacement des appels async_write dans Boost Asio

Dans les systèmes distribués, il est courant que les clients envoient des messages aux serveurs de manière asynchrone. Pour gérer les messages entrants, les serveurs implémentent généralement un mécanisme basé sur une file d'attente dans lequel les messages sont traités séquentiellement dans l'ordre dans lequel ils sont reçus. Cependant, il existe certains scénarios dans lesquels les messages peuvent s'entrelacer, entraînant un comportement inattendu.

Description du problème

Considérez un scénario impliquant un serveur qui reçoit des messages de plusieurs clients simultanément. Les messages de chaque client sont traités de manière asynchrone à l'aide de async_write. Si les clients envoient des messages à un rythme rapide, il est possible que les appels async_write soient entrelacés, ce qui entraîne un traitement des messages dans le désordre.

Solution : approche basée sur la file d'attente

Pour éviter Pour l'entrelacement des appels async_write, une approche basée sur la file d'attente peut être utilisée. Voici comment cela fonctionne :

  1. Chaque client dispose d'une file d'attente de messages sortants dédiée.
  2. Lorsqu'un client envoie un message, il est ajouté à la file d'attente sortante.
  3. Le serveur vérifie la taille de la file d'attente sortante pour chaque client.
  4. Si la file d'attente n'est pas vide, le serveur lance une opération async_write pour envoyer le premier message de la file d'attente.
  5. Une fois l'opération async_write terminée, le serveur vérifie à nouveau la file d'attente.
  6. S'il y a plus de messages dans la file d'attente, une autre opération async_write est lancée.
  7. 🎜>
  8. Ce processus se répète jusqu'à ce que tous les messages de la file d'attente aient été envoyés avec succès.

Mise en œuvre Exemple

L'extrait de code suivant montre comment implémenter cette approche basée sur la file d'attente :
// Include necessary headers
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <deque>
#include <iostream>
#include <string>

class Connection
{
public:
    Connection(
            boost::asio::io_service&amp; io_service
            ) :
        _io_service( io_service ),
        _strand( _io_service ),
        _socket( _io_service ),
        _outbox()
    {

    }

    void write( 
            const std::string&amp; message
            )
    {
        _strand.post(
                boost::bind(
                    &amp;Connection::writeImpl,
                    this,
                    message
                    )
                );
    }

private:
    void writeImpl(
            const std::string&amp; message
            )
    {
        _outbox.push_back( message );
        if ( _outbox.size() > 1 ) {
            // outstanding async_write
            return;
        }

        this->write();
    }

    void write()
    {
        const std::string&amp; message = _outbox[0];
        boost::asio::async_write(
                _socket,
                boost::asio::buffer( message.c_str(), message.size() ),
                _strand.wrap(
                    boost::bind(
                        &amp;Connection::writeHandler,
                        this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                        )
                    )
                );
    }

    void writeHandler(
            const boost::system::error_code&amp; error,
            const size_t bytesTransferred
            )
    {
        _outbox.pop_front();

        if ( error ) {
            std::cerr << "could not write: " << boost::system::system_error(error).what() << std::endl;
            return;
        }

        if ( !_outbox.empty() ) {
            // more messages to send
            this->write();
        }
    }


private:
    typedef std::deque<std::string> Outbox;

private:
    boost::asio::io_service&amp; _io_service;
    boost::asio::io_service::strand _strand;
    boost::asio::ip::tcp::socket _socket;
    Outbox _outbox;
};

int
main()
{
    boost::asio::io_service io_service;
    Connection foo( io_service );
}

Conclusion

En implémentant une approche basée sur la file d'attente, l'entrelacement des appels async_write peuvent être efficacement évités, en garantissant que les messages sont traités dans le bon ordre. Ceci est particulièrement important dans les scénarios où l'ordre de traitement des messages a un impact significatif sur la fonctionnalité globale du système.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn