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

时间:2015-02-04 12:04:28

标签: c++ c++11 tcp boost-asio

服务器接受新连接:

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的例子没有提到如何做到这一点。而且我找不到相关资源。

1 个答案:

答案 0 :(得分:1)

我希望我能正确地解决您的问题,并且您还想了解asio如何使用异步操作。

简而言之,一切都发生在run对象的io_service函数中。 当您在某个函数中调用async_writeasync_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之类的异步操作来注册其他回调并从客户端写入/读取数据。