【问题标题】:Problem with async_read when packet length is more or less当数据包长度或多或少时 async_read 出现问题
【发布时间】:2020-07-23 22:58:10
【问题描述】:

我检查了一个 Boost 示例并进行了很多测试,但我认为当数据包(接收到的数据)小于或大于其预期缓冲区时,async_read 不会被正确调用。

在 boost.org 上有 a server 和 a client SSL 示例。在握手完成后的客户端示例中,send_request() 被调用,然后send_request() 被发送文本的确切长度。如果send_request() 不知道数据包的长度会怎样?

这有三种情况(缓冲区长度是指boost::asio::buffer(reply_, length) 中的length 参数):

包长度等于缓冲区长度

没问题,我们收到了数据包。

数据包长度大于缓冲区长度

我们得到与数据包长度一样多的数据,剩下的将在另一轮接收。问题是我们无法通过将另一个 send_request() 放入 lambda 主体来获取数据包的其余部分。当另一个send_request() 被调用(等等)时,我们将得到的残骸:

void receive_response(std::size_t length)
{
    boost::asio::async_read(
        socket_,
        boost::asio::buffer(reply_, length),
        [this](const boost::system::error_code& error, std::size_t length)
        {
            if (!error)
            {
                std::cout << "Reply: ";
                std::cout.write(reply_, length);
                std::cout << "\n";
                receive_response(length);            <---- This one
            }
            ...
        }
    );
}

数据包长度小于缓冲区长度

我稍微更改了握手 la​​mbda,以便我可以模拟这个,就像下面的代码一样。我还更改了receive_response() 和send_request() 方法,使它们不会相互调用。我预计 async_read(receive_response())的 lambda 在两个 async_writes(send_request())填充缓冲区后被调用,但它没有。

void handshake()
{
    socket_.async_handshake(
        boost::asio::ssl::stream_base::client,
        [this](const boost::system::error_code& error)
        {
            if (!error)
            {
                receive_response(10);        // Trigger async_read for length 10
                send_request();                // Send a string of length 5
                send_request();                // Send a string of length 5
            }
            ...
        }
    );
}

有人可能会建议使用async_read_some()。我也测试过。幸运的是,它被第一个 send_request() 调用,但第二个 send_request() 没有调用 async_read_some() lambda(我在 lambda 的主体中放置了另一个 receive_response() 以进行循环)。

void receive_response(std::size_t length)
{
    socket_.async_read_some(
        boost::asio::buffer(reply_, length),
        [this](const boost::system::error_code& error, std::size_t length)
        {
            ...
            receive_response(length);
            ...
        }
    );
}

【问题讨论】:

  • 这个问题似乎混合了send_request() 和receive_response。显然,发送者知道发送了多少数据。

标签: c++ asynchronous network-programming boost-asio


【解决方案1】:

SSL 没有那么重要。它是一个流,类似于 TCP。

这意味着接收方无法知道将发送多少数据。发送者总是可以发送另一个字节。因此,在boost::asio::async_read 之后,你应该处理你能做的,保留你不能做的。

显然,您不能将第一次调用的数据保存在第二次调用boost::asio::async_read 将存储下一个结果的位置。那只会覆盖您想要保留的结果。有很多解决方案:使用第二个缓冲区,或者记住 _reply 中已有多少字节,然后创建一个 boost::asio::buffer(_reply+offset, length-offset) 缓冲区。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-06
    • 2022-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多