C++ 不调用异步调用

C++ 不调用异步调用,c++,asynchronous,boost-asio,C++,Asynchronous,Boost Asio,我的代码中有一个非常奇怪的bug,但我真的无法理解到底出了什么问题。我试图实现一个非常简单的客户端,通过套接字将文件发送到服务器 文件以以下方式发送: 连接到服务器 发送包含文件信息的标题(当前文件名和大小) 而块是可用的 从文件中读取字节块 发送区块的标头 发送区块的数据 在Boost.Asio中,它变成: async_connect( // 1. async_write( // 2. while (file) // 3. async_write

我的代码中有一个非常奇怪的bug,但我真的无法理解到底出了什么问题。我试图实现一个非常简单的客户端,通过套接字将文件发送到服务器

文件以以下方式发送:

  • 连接到服务器
  • 发送包含文件信息的标题(当前文件名和大小)
  • 而块是可用的
  • 从文件中读取字节块
  • 发送区块的标头
  • 发送区块的数据
  • 在Boost.Asio中,它变成:

      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
    多次,在它完成之前,套接字是否会死锁?