How to trigger an โ€œeventโ€ when my Boost :: asio tcp server (AKA io_service.run ()) only starts?

Based on the client / server relations boost :: asio, I should run the client program from the server program only when the server thread is in the < waiting state for connection . <w>
My question is how to get knowledge about this condition?

As an example, use the asio link example / serialization and replace the main server.cpp function with this 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
source share
1 answer

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


This may be easier to understand by distinguishing between state and operations. The state determines what the OS can do with the object; the application initiates operations that perform actions and may depend on the state. For example, when a socket is in the open state, the OS will queue data; a read operation retrieves data in a queue. The same applies to acceptors. When the acceptor is in the listening state, the OS will establish queues in the connections; the accept operation terminates the connection by removing it from the queue.

An acceptor [state] 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() <----' 

Various overloaded constructors will cause the acceptor begin its lifetime in a closed, open, or listened state. In the case of s11n_example::server acceptor is built with an endpoint, so this overload will cause the acceptor to be in a post-state state. This is equivalent to:

 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 the server is built 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 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(); } 

It should be noted that Boost.Asio acceptors do not provide:

  • Reactor-based operations for receiving compounds. Thus, it is not possible to determine when the connection is ready to be accepted (i.e., the connection is queued and expects to be accepted).
  • Higher detection if acceptor is in listening state. However, this can be accomplished by requesting a native_handle acceptor. For example, using getsockopt() to get the value of SOL_SOCKET/SO_ACCEPTCONN .
+4
source

All Articles