C++ 不调用异步调用
我的代码中有一个非常奇怪的bug,但我真的无法理解到底出了什么问题。我试图实现一个非常简单的客户端,通过套接字将文件发送到服务器 文件以以下方式发送:C++ 不调用异步调用,c++,asynchronous,boost-asio,C++,Asynchronous,Boost Asio,我的代码中有一个非常奇怪的bug,但我真的无法理解到底出了什么问题。我试图实现一个非常简单的客户端,通过套接字将文件发送到服务器 文件以以下方式发送: 连接到服务器 发送包含文件信息的标题(当前文件名和大小) 而块是可用的 从文件中读取字节块 发送区块的标头 发送区块的数据 在Boost.Asio中,它变成: async_connect( // 1. async_write( // 2. while (file) // 3. async_write
async_connect( // 1.
async_write( // 2.
while (file) // 3.
async_write( // 3.2
async_write( // 3.3
)
)
)
问题是我从来没有达到3.2(应该发送区块头的函数)。看来程序卡住了。我还试着往里面扔一扔,看看它是否撞坏了
下面是一个简短的片段:
namespace net = boost::asio;
namespace fs = std::filesystem;
using net::ip::tcp;
class Client {
public:
Client(net::io_context &io_context, const tcp::resolver::results_type &endpoints) {
net::async_connect(socket_, endpoints, [this](const auto &, auto) { sendMessageHeader(); });
}
private:
void sendHeader() {
// Prepare message
// ...
net::async_write(socket_, net::buffer(header_.data(), header_length()),
[this](const auto &, auto) { sendChunks(); });
}
void sendChunks() {
// ...
while(file) {
// prepare the chunk header
// ...
chunkHeaderQueue_.push();
chunkBufferQueue_.push();
// send the header
net::async_write(socket_, net::buffer(chunkHeaderQueue_.front().data(), chunkHeaderQueue_.front().size),
[this](const auto&, auto) {
auto &chunk = chunkBufferQueue_.front();
chunkHeaderQueue_.pop();
net::async_write(socket_, net::buffer(chunk), [this](const auto&, auto) {
chunkBufferQueue_.pop();
});
});
}
}
private:
boost::asio::io_context &io_context_;
tcp::socket socket_;
MessageHeader header_;
ChunkHeaderQueue chunkHeaderQueue_;
ChunkBufferQueue chunkBufferQueue_;
};
int main(int argc, char *argv[]) {
// used for async operations
net::io_context io_context;
// resolver will connect to the server
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(argv[1], argv[2]);
// create the client and start all async operations
Client client(io_context, endpoints, {argv[3]});
// it will block until all async operation will be done!
io_context.run();
} catch (std::exception &e) {
fmt::print("Exception: {}\n", e.what());
}
return 0;
}
在
sendChuncks
中,您在套接字上发出多次写入操作,而不等待完成。您还可以从chunkBufferQueue\弹出两次
异步操作不应该像这样使用,它们应该链接起来,您的函数应该像这样:
void sendChunk()
{
auto& chunk = chunkBufferQueue_.front();
net::async_write(socket_, net::buffer(chunck),
[this](const auto&, auto) {
chunkBufferQueue_.pop();
sendHeader();
});
}
void sendHeader()
{
if(!file)
return;
chunkHeaderQueue_.push();
chunkBufferQueue_.push();
auto& header = chunkHeaderQueue_.front();
net::async_write(socket_, net::buffer(chunck),
[this](const auto&, auto) {
chunkHeaderQueue_.pop();
sendChunk();
});
}
为什么要将区块存储为引用,自动和区块
?您参考front
,然后调用pop
?这是未定义的行为。通过弹出删除对象,是什么使指针悬空。如果将for循环与async\u XXX
一起使用,这是一个相当糟糕的主意。您应该等到调用正确的处理程序,然后调用下一个async\u XXX
调用。如果要使用for循环,请调用asio的同步函数。由于套接字i/o处于死锁状态,程序将挂起:在完成第一次写入之前,请尝试在套接字上开始另一次写入。这是行不通的。在这种情况下,异步意味着与程序的其余部分(而不是对套接字的写入)相关的异步。重新构造程序,以便将所有的头和块放在一个队列中,然后在另一个线程中从队列中拉出块,并将它们同步地推送到套接字。因此,如果我调用async\u write
多次,在它完成之前,套接字是否会死锁?