首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当数据包长度或多或少时,async_read会出现问题

当数据包长度或多或少时,async_read会出现问题
EN

Stack Overflow用户
提问于 2020-04-11 14:49:13
回答 1查看 213关注 0票数 0

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

在boost.org上有a servera client SSL示例。在客户端示例中,握手完成后,将调用send_request(),然后使用所发送文本的确切长度执行send_request()。如果send_request()不知道数据包的长度,会发生什么?

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

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

没问题,我们收到包裹了。

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

我们得到和包长度一样多的包,剩下的包在另一个轮次中被接收。问题是我们不能通过在lambda主体中放入另一个send_request()来获取包的其余部分。当调用另一个send_request() (以此类推)时,我们将得到的剩余部分:

代码语言:javascript
复制
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
            }
            ...
        }
    );
}

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

我对握手lambda做了一些修改,这样我就可以模拟这个握手了,就像下面这段代码一样。我还更改了receive_response()send_request()方法,使它们不会相互调用。我期望async_read (在receive_response()中)的lambda在两个async_write(在send_request()中)填满缓冲区后被调用,但它没有。

代码语言:javascript
复制
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()没有调用lambdaλ(我已经在async_read_some()的主体中放入了另一个receive_response()来进行循环)。

代码语言:javascript
复制
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);
            ...
        }
    );
}
EN

回答 1

Stack Overflow用户

发布于 2020-08-18 22:25:14

SSL并不是那么相关。它是一个流,就像TCP一样。

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61153075

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档