我检查了一个Boost示例并进行了大量测试,但我认为当数据包(接收到的数据)小于或大于其预期缓冲区时,async_read不会被正确调用。
在boost.org上有a server和a client SSL示例。在客户端示例中,握手完成后,将调用send_request(),然后使用所发送文本的确切长度执行send_request()。如果send_request()不知道数据包的长度,会发生什么?
有三种情况(缓冲区的长度,我指的是boost::asio::buffer(reply_, length)中的length参数):
数据包长度等于缓冲区长度
没问题,我们收到包裹了。
数据包长度大于缓冲区长度
我们得到和包长度一样多的包,剩下的包在另一个轮次中被接收。问题是我们不能通过在lambda主体中放入另一个send_request()来获取包的其余部分。当调用另一个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
}
...
}
);
}数据包长度小于缓冲区长度
我对握手lambda做了一些修改,这样我就可以模拟这个握手了,就像下面这段代码一样。我还更改了receive_response()和send_request()方法,使它们不会相互调用。我期望async_read (在receive_response()中)的lambda在两个async_write(在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()没有调用lambdaλ(我已经在async_read_some()的主体中放入了另一个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);
...
}
);
}发布于 2020-08-18 22:25:14
SSL并不是那么相关。它是一个流,就像TCP一样。
这意味着接收方无法知道将发送多少数据。发送者总是可以发送另一个字节。因此,在boost::asio::async_read之后,您应该处理您可以处理的内容,并保留您不能处理的内容。
显然,您不能将第一次调用的数据保存在第二次boost::asio::async_read调用将存储下一次结果的相同位置。这只会覆盖您想要保留的结果。有许多解决方案:使用第二个缓冲区,或者记住您的_reply中已经有多少字节,并在此基础上创建一个boost::asio::buffer(_reply+offset, length-offset)缓冲区。
https://stackoverflow.com/questions/61153075
复制相似问题