如何发起“事件"当我的 Boost::asio tcp 服务器刚开始运行时(又名 io_service.run() )?
基于 boost::asio 客户端/服务器关系,只有当服务器线程处于等待连接"状态时,我才必须从服务器程序启动客户端程序.
我的问题是如何知道那个状态?
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 ?
作为示例,使用 asio 示例/序列化link,并替换掉main函数带有该代码的 server.cpp:
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;
}
谢谢,
推荐答案
简而言之,s11n_example::server
处于这样一种状态:在构造函数调用完成后,传入的连接将立即排队.
In short, s11n_example::server
is in a state where incoming connections will be queued immediately after the constructor call has completed.
通过定义状态和操作之间的区别可能更容易理解这一点.状态决定了操作系统可以对对象做什么;应用程序启动执行操作的操作,并且可能取决于状态.例如,当套接字处于 open 状态时,操作系统会将数据排队;read 操作检索排队的数据.这同样适用于接受者.当接受者处于 listen 状态时,操作系统会将连接排队;accept 操作将完成连接,将其从队列中移除.
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.
一个acceptor
的[states]和transitions()如下:
.----> [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() <----'
各种重载构造函数将导致 acceptor
在关闭、打开或侦听状态下开始其生命周期.对于 s11n_example::server
,acceptor 是用端点构造的,所以 这个 重载将导致接受器在构造后处于侦听状态.这相当于做:
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
因此,promise 可以在 server
构建之后,io_service.run()
之前设置:
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();
}
需要注意的一个微妙之处是 Boost.Asio 的接受器不提供:
One subtlety to note is that Boost.Asio's acceptors do not provide:
- 用于接受连接的基于反应器的操作.因此,无法检测到连接何时准备好接受(即连接已排队等待接受).
- 一种检测
acceptor
是否处于监听状态的高级方法.然而,这可以通过查询接受者的native_handle
.例如,使用getockopt()
获取SOL_SOCKET/SO_ACCEPTCONN
的值.
- 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'snative_handle
. For example, usinggetsockopt()
to get the value ofSOL_SOCKET/SO_ACCEPTCONN
.
相关文章