asio:服务器如何在监听客户端的同时主动向客户端发送信息?

asio :how does server actively send information to client while listening to client at the same time?

服务器接受新连接:

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();
    });
}

会话->开始的工作方式如下:

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()递归之外主动向客户端发送信息?我需要服务器向所有客户端分派一些由未来用户输入决定的工作。 boost asio c++11 示例没有提到如何去做。我在上面找不到相关资源。

希望我能正确回答你的问题,你也想了解 asio 如何处理异步操作。

简而言之,一切都发生在 io_service 对象的 run 函数中。 当您在某个函数中调用 async_writeasync_read 时,您注册了一个回调(当某些事件发生时将被调用),然后立即 return 到该函数。然后,当所有回调都注册后,它 returns in run 并等待事件。

所以我会尽量详细解释你的代码。方法 run 是一种无限循环,它检查事件是否已经发生。首先,您使用 acceptor_.async_accept、return 到 run 注册回调并等待。当客户端连接时,accept 事件的回调被调用,你在 session->start 中用 boost::asio::async_read 注册一个回调(我猜是这个,因为你没有提供 do_read_header 源),注册再次在 do_accept 中回调,return 到 run 并等待新的客户端或数据。收到数据后,您调用 write 并使用 boost::asio::async_write 注册另一个回调,依此类推...最后仍然是 return 到 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 中)来注册其他回调和 write/read来自客户的数据。