How to launch an “event” when my Boost::asio tcp server just start running ( AKA io_service.run() )?

冷暖自知 提交于 2019-11-27 06:31:41

问题


Based on an boost::asio client/server relationship, I have to launch the client program from the server program only when the server thread is in a "waiting to be connected" state.

My question is how to have the knowledge of that state ?

As a sample use the asio example/serialization link, and replace the main function of server.cpp with that 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;
}

Thanks,


回答1:


In short, s11n_example::server is in a state where incoming connections will be queued immediately after the constructor call has completed.


It may be easier to understand this by defining a distinction between state and operations. A state determines what the OS can do with the object; an application initiates operations that perform actions and may depend on state. For example, when a socket in an open state, the OS will queue data; a read operation retrieves the queued data. The same applies to the acceptors. When an acceptor is in a listen state, the OS will queue connections; an accept operation will complete the connection, removing it from the queue.

An acceptor's [states] and transitions() are as follows:

     .----> [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() <----'

The various overloaded constructors will result in the acceptor starting its lifetime in a closed, opened, or listening state. In the case of s11n_example::server, the acceptor is constructed with an endpoint, so this overload will result in the acceptor being in a listening state post-construction. It is the equivalent of doing:

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

Therefore, the promise can be set after server is constructed and before 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();
}

One subtlety to note is that Boost.Asio's acceptors do not provide:

  • Reactor based operations for accepting connections. Thus, it is not possible to detect when a connection is ready to be accepted (i.e. a connection is queued and waiting to be accepted).
  • An higher-level way to detect if the acceptor is in a listening state. Nevertheless, this may be accomplished by querying the acceptor's native_handle. For example, using getsockopt() to get the value of SOL_SOCKET/SO_ACCEPTCONN.


来源:https://stackoverflow.com/questions/15829165/how-to-launch-an-event-when-my-boostasio-tcp-server-just-start-running-aka

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!