了解beast::tcp_stream中timeout的用法?

Understand the usage of timeout in beast::tcp_stream?

参考:

https://www.boost.org/doc/libs/1_78_0/libs/beast/example/websocket/client/async/websocket_client_async.cpp https://www.boost.org/doc/libs/1_78_0/libs/beast/doc/html/beast/using_io/timeouts.html https://www.boost.org/doc/libs/1_78_0/libs/beast/doc/html/beast/ref/boost__beast__tcp_stream.html

    void on_resolve(beast::error_code ec, tcp::resolver::results_type results)
    {
        if(ec) return fail(ec, "resolve");
        // Set the timeout for the operation
        beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));

        // Make the connection on the IP address we get from a lookup
        beast::get_lowest_layer(ws_).async_connect(
            results, beast::bind_front_handler(
                &session::on_connect, shared_from_this()));
    }

    void on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep)
    {
        if(ec) return fail(ec, "connect");

        // Turn off the timeout on the tcp_stream, because
        // the websocket stream has its own timeout system.
        // beast::get_lowest_layer(ws_).expires_never(); // Note: do NOT call this line for this question!!!

...
        host_ += ':' + std::to_string(ep.port());
        // Perform the websocket handshake
        ws_.async_handshake(host_, "/",
            beast::bind_front_handler(&session::on_handshake, shared_from_this()));
    }

问题 1> beast::tcp_stream 的超时是否会在上一个异步操作按时完成后继续工作?

例如, 在上面的示例中,超时将在 30 秒后到期。如果 async_connect 没有在 30 秒内完成,session::on_connect 将收到一个 error::timeout 作为 ec 的值。假设 async_connect 需要 10 秒, 我可以假设 async_handshake 需要在 20(即 30-10)秒内完成,否则 error::timeout 将被发送到 session::on_handshake 吗?我根据 on_connect 函数中的注释推断出这个想法(即

Turn off the timeout on the tcp_stream

)。换句话说,超时只有在它完成指定的有效期或被 expires_never 禁用后才会被关闭。我的理解正确吗?

问题 2> 另外我想知道在 async_callingasync_callback 函数中我应该使用什么好的超时模式。

当我们调用 async_calling 操作时:

void func_async_calling()
{
  // set some timeout here(i.e. XXXX seconds)
  Step 1> beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(XXXX));
  Step 2> ws_.async_operation(..., func_async_callback, )
  Step 3> beast::get_lowest_layer(ws_).expires_never();
}

当我们为异步操作定义一个async_callback句柄时:

void func_async_callback()
{
  Step 1>Either call 
    // Disable the timeout for the next logical operation.
    beast::get_lowest_layer(ws_).expires_never(); 
  or
    // Enable a new timeout
    beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(YYYY));

  Step 2> call another asynchronous function
  Step 3> beast::get_lowest_layer(ws_).expires_never();
}

这有意义吗?

谢谢

问题 1

是的,没错。链接页面有确认:

// The timer is still running. If we don't want the next
// operation to time out 30 seconds relative to the previous
// call  to `expires_after`, we need to turn it off before
// starting another asynchronous operation.

stream.expires_never();

问题 2

看起来不错。我能想到的唯一微妙之处是

  • 经常,因为 Thread Safety 通常启动和完成都发生在同一条(隐式)链上。

    如果是这样,那么在您的完成处理程序示例中,expires_never(); 将是多余的。

  • 如果完成处理程序在同一条链上,您要主动避免触及到期时间,因为那将是数据竞争

  • 另一种模式是为较长的剧集(例如 client/server 之间的 multi-message 对话)仅设置一次过期。显然在这种模式下,没有人会在初始设置后触及到期日。这看起来很明显,但我想我会在有人将这种模式牢牢地抛在石头上再也不会考虑之前提及它。

总是做你需要的,喜欢简单的代码。我认为您对该功能的基本理解是正确的。 (难怪,this documentation是一件艺术品)。