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

前端 未结 1 1003
长情又很酷
长情又很酷 2020-12-10 22:44

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 c

相关标签:
1条回答
  • 2020-12-10 23:35

    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.
    0 讨论(0)
提交回复
热议问题