服务器接受新连接:
void do_accept()
{
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec)
{
if (!ec)
{
connection_count++;
all_session.push_back(std::make_shared<session>(std::move(socket_), io_service_));
all_session.back()->start();
}
do_accept();
});
}
并且session-&gt; start的工作原理如下:
void start()
{
std::cout << "connection from " << socket_.remote_endpoint().address() << std::endl;
do_read_header();
}
do_read_header处理消息然后递归调用自身。处理消息时,它会调用write向客户端发送一些信息。 写函数如下:
void write(const chat_message& msg)
{
write_msgs_ = msg;
do_write(msg.length());
}
void do_write(std::uint32_t length)
{
auto self(shared_from_this());
boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.data(), length),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read_header();
}
});
}
接下来是问题:服务器如何在do_read_header()递归之外主动向客户端发送信息?我需要服务器调度一些工作,这是由未来用户输入决定给所有客户端。 提升asio c ++ 11的例子没有提到如何做到这一点。而且我找不到相关资源。
答案 0 :(得分:1)
我希望我能正确地解决您的问题,并且您还想了解asio如何使用异步操作。
简而言之,一切都发生在run
对象的io_service
函数中。
当您在某个函数中调用async_write
或async_read
时,您会注册一个回调(在某些事件发生时将调用),然后立即返回该函数。然后,当所有回调都被注册时,它将返回run
并等待事件。
因此,我将尝试详细解释您的代码。方法run
是一种无限循环,它检查事件是否发生。首先,您使用acceptor_.async_accept
注册回调,返回run
并等待。当客户端连接时,调用accept事件的回调,并在boost::asio::async_read
中注册session->start
的回调(我猜这个,因为你没有提供do_read_header
源),注册再次回调do_accept
,返回run
并等待新客户端或数据。收到数据后,您拨打write
并使用boost::asio::async_write
注册另一个回调,依此类推......最后仍然会返回run
。
由于run
是阻塞函数,如果您需要处理来自其他源(例如服务器控制台)的输入,您可以执行以下操作之一:
1)使用run_one
run
。编写自己的循环,调用run_one
并处理其他操作。
2)在另一个线程中调用run
(也将在此线程中处理与io_service
相关的所有操作),而在主线程中处理其他操作。这是一个小例子:
// here we process all network (or other) operations associated with io_service
void run( boost::asio::io_service& io_service ) {
while( true ) {
try {
io_service.run();
break; // run() exited normally
}
catch( std::exception& e) {
// Deal with exception as appropriate.
}
}
}
int main( ) {
...
boost::asio::io_service io_service;
...
// start io_service.run( ) in separate thread
auto t = std::thread( &run, std::ref( io_service ) );
...
while( true ) {
std::string line;
// read line from console
std::getline( std::cin, line );
// process input
if( line == "stop" ) {
io_service.stop( );
break;
} else {
send_to_everyone( line );
}
}
}
io_service
是线程安全的,因此您可以安全地在主线程(例如boost::asio::async_write
中)中使用send_to_everyone
之类的异步操作来注册其他回调并从客户端写入/读取数据。