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
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:
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
.