started - sourceforge boost c++



Comment lancer un "événement" quand mon serveur Boost:: asio tcp démarre(AKA io_service.run())? (1)

Basé sur une relation client / serveur boost :: asio, je dois lancer le programme client à partir du programme serveur uniquement lorsque le thread serveur est dans un état "en attente d'être connecté ".

Ma question est comment avoir la connaissance de cet état?

Comme exemple, utilisez l' exemple / lien de sérialisation asio et remplacez la fonction principale de server.cpp par ce code:

#include <conio.h>
#include <concrt.h> // wait function
#include <future>
#include <thread>

void server_thread( std::promise<bool>& run )
{ 
    boost::asio::io_service io_service;
    s11n_example::server server(io_service, 123);
    // too early to run.set_value( true );
    io_service.run();
    // too late to run.set_value( true );
}

int main(int argc, char* argv[])
{
    std::promise<bool> run;
    std::thread thrd( server_thread, boost::ref( run ) );
    thrd.detach(); 

    bool launched = run.get_future().get();
    // server is waiting for connection
    // launch the client
    if( launched )
    {
        int rc = system( "start client.exe localhost 123" );
        if( rc )
            std::cerr << "system failed returning " << rc << std::endl ;
    }
    else
        std::cerr << "server_thread failure" << std::endl ;

    std::cout << "hit a key to exit"  ;
    while( !_kbhit() )
        Concurrency::wait( 100 );

    return 0;
}

Merci,


En bref, s11n_example::server est dans un état où les connexions entrantes seront mises en file d'attente immédiatement après la fin de l'appel du constructeur.

Il peut être plus facile de comprendre cela en définissant une distinction entre l'état et les opérations. Un état détermine ce que l'OS peut faire avec l'objet; une application lance des opérations qui effectuent des actions et peuvent dépendre de l'état. Par exemple, lorsqu'une socket est dans un état ouvert , le système d'exploitation met en file d'attente les données; une opération de lecture récupère les données mises en file d'attente. La même chose s'applique aux accepteurs. Lorsqu'un accepteur est dans un état d' écoute , le système d'exploitation placera les connexions en file d'attente; une opération d' acceptation complètera la connexion, la retirant de la file d'attente.

Les [états] et les transitions () d' un acceptor sont les suivants:

     .----> [closed] ------.     [closed]:    socket not open
     |                     |     [opened]:    socket open but not listening for
     |                     V                  connections
  close() <------.      open()   [listening]: incoming connections will be
     ^           |         |                  queued until accepted(), causing
     |           |         V                  the connection to be established
[listening]      '---- [opened]
     ^                     |
     |                     |
     '------ listen() <----'

Les divers constructeurs surchargés feront que l' acceptor commencera sa durée de vie dans un état fermé, ouvert ou en écoute. Dans le cas de s11n_example::server , l'accepteur est construit avec un point de terminaison, de sorte que cette surcharge aura pour résultat que l'accepteur soit dans un état d'écoute après la construction. C'est l'équivalent de faire:

using boost::asio::ip::tcp;
tcp::endpoint endpoint_(tcp::v4(), 123);
tcp::acceptor acceptor_(io_service); // closed state
acceptor.open(endpoint_.protocol()); // opened state
acceptor.bind(endpoint);
acceptor.listen();                   // listening state

Par conséquent, la promesse peut être définie après la construction du server et avant io_service.run() :

void server_thread(std::promise<bool>& run)
{ 
    boost::asio::io_service io_service;
    s11n_example::server server(io_service, 123);
    // The server's acceptor is in a listening state, so connection attempts
    // will be queued even without the io_service event loop running.  The
    // server also has an outstanding asynchronous accept operation.
    run.set_value(true);
    // Run the service, this will start an asynchronous loop that accepts 
    // connections.
    io_service.run();
}

Une subtilité à noter est que les accepteurs de Boost.Asio ne fournissent pas:

  • Opérations basées sur un réacteur pour accepter des connexions. Ainsi, il n'est pas possible de détecter quand une connexion est prête à être acceptée (c'est-à-dire qu'une connexion est mise en attente et attend d'être acceptée).
  • Une méthode de niveau supérieur pour détecter si l' acceptor est dans un état d'écoute. Néanmoins, cela peut être accompli en interrogeant la native_handle l'accepteur. Par exemple, en utilisant getsockopt() pour obtenir la valeur de SOL_SOCKET/SO_ACCEPTCONN .