代码之家  ›  专栏  ›  技术社区  ›  Jon Lachmann

Boost asio,async_receive_from内的计时器不会触发

  •  0
  • Jon Lachmann  · 技术社区  · 1 年前

    我正在尝试使用Boost asio编写一个小型UDP代理。在其中,我需要读取一个套接字,如果该套接字接收到数据报,则应在特定时间后触发回调,转发数据报。它还应该立即准备好接收新的数据报。

    我的问题是,当我的代码不在类中时,它可以工作,但一旦我尝试将其创建为类,代码就会停止工作。我很确定我错过了一些关键的东西,因为我对异步增强非常陌生。

    工作的代码看起来是这样的,我得到了计时器按预期命中的输出。

    #include <iostream>
    #include <boost/asio.hpp>
    
    void receive(udp::socket &socket, io_context &ioContext) {
        udp::endpoint receive_endpoint;
        std::array<char, 8192> buf;
        socket.async_receive_from(buffer(buf, buf.size()), receive_endpoint,
                                  [&](const boost::system::error_code& error, std::size_t bytesReceived) {
            if (!error && bytesReceived > 0) {
                std::cout << "Got a package" << std::endl;
                boost::asio::steady_timer timer = boost::asio::steady_timer(ioContext, boost::asio::chrono::milliseconds(100));
                timer.async_wait([&](const boost::system::error_code& ec) {
                    std::cout << "Timer hit" << std::endl;
                });
                receive(socket, ioContext);
            } else {
                std::cout << "Error receiving data from client" << std::endl;
            }
        });
    }
    
    int main() {
        boost::asio::io_context ioContext;
        udp::socket socket(ioContext);
        socket.open(udp::v4());
        udp::endpoint localEndpoint(ip::address::from_string("127.0.0.1"), 12345);
        socket.bind(localEndpoint);
        receive(socket, ioContext);
    
        ioContext.run();
    
        return 0;
    }
    

    当我把它做成一个类时,计时器永远不会响。使用该类时,主文件的代码如下所示:

    #include "udp_class.h"
    #include <iostream>
    #include <boost/asio.hpp>
    
    int main() {
        boost::asio::io_context ioContext;
        Proxy my_proxy(ioContext);
        my_proxy.start();
        ioContext.run();
    
        return 0;
    }
    

    类定义为

    #pragma once
    
    #define BOOST_ASIO_ENABLE_HANDLER_TRACKING
    #include <iostream>
    #include <boost/asio.hpp>
    #include <chrono>
    
    using namespace boost::asio;
    using ip::udp;
    using std::chrono::milliseconds;
    
    class Proxy {
    public:
        Proxy(io_context& ioContext): localSocket_(ioContext) { };
        void start() {
            localSocket_.open(udp::v4());
            localSocket_.bind(udp::endpoint(ip::address::from_string("127.0.0.1"), 12345));
            receive();
        };
    
    private:
        void receive() {
            udp::endpoint receive_endpoint;
            std::array<char, 8192> buf;
            localSocket_.async_receive_from(buffer(buf, buf.size()), receive_endpoint,
                    [&](const boost::system::error_code& error, std::size_t bytesReceived) {
                  if (!error && bytesReceived > 0) {
                      std::cout << "Got a package" << std::endl;
                      boost::asio::steady_timer timer = boost::asio::steady_timer(ioContext, boost::asio::chrono::milliseconds(100));
                      timer.async_wait([&](const boost::system::error_code& ec) {
                          std::cout << "Timer hit" << std::endl;
                      });
                      receive();
                  } else {
                      std::cout << "Error receiving data from client" << std::endl;
                  }
              });
        }
    
        io_context ioContext;
        udp::socket localSocket_;
    };
    

    这会接收到一个数据报,注意到控制台,但计时器永远不会命中。

    boost asio调试的输出如下所示:

    @asio|1720035449.638484|0*1|[email protected]_receive_from
    @asio|1720035449.638495|.1|non_blocking_recvfrom,ec=system:35,bytes_transferred=0
    @asio|1720035451.692791|.1|non_blocking_recvfrom,ec=system:0,bytes_transferred=12
    @asio|1720035451.692827|>1|ec=system:0,bytes_transferred=12
    @asio|1720035451.692951|1*2|[email protected]_wait
    @asio|1720035451.692976|1*3|[email protected]_receive_from
    @asio|1720035451.692987|.3|non_blocking_recvfrom,ec=system:35,bytes_transferred=0
    @asio|1720035451.692992|1|[email protected]
    @asio|1720035451.692998|<1|
    

    我已经被这个和类似的问题困扰了几天,我真的无法理解我做错了什么。我提取了我的整个代码,并提炼出这个例子,希望它能尽可能简洁地代表问题所在。

    1 回复  |  直到 1 年前
        1
  •  1
  •   h0x91B    1 年前

    你正在创建一个新的 io_context 在Proxy类内部,但使用传递给套接字构造函数的那个。这种不匹配导致了问题。

    固定类别:

    #pragma once
    
    #define BOOST_ASIO_ENABLE_HANDLER_TRACKING
    #include <iostream>
    #include <boost/asio.hpp>
    #include <chrono>
    
    using namespace boost::asio;
    using ip::udp;
    using std::chrono::milliseconds;
    
    class Proxy {
    public:
        Proxy(io_context& io): ioContext(io), localSocket_(io) { };
        void start() {
            localSocket_.open(udp::v4());
            localSocket_.bind(udp::endpoint(ip::address::from_string("127.0.0.1"), 12345));
            receive();
        };
    
    private:
        void receive() {
            udp::endpoint receive_endpoint;
            std::array<char, 8192> buf;
            localSocket_.async_receive_from(buffer(buf, buf.size()), receive_endpoint,
                    [this](const boost::system::error_code& error, std::size_t bytesReceived) {
                  if (!error && bytesReceived > 0) {
                      std::cout << "Got a package" << std::endl;
                      auto timer = std::make_shared<boost::asio::steady_timer>(ioContext, boost::asio::chrono::milliseconds(100));
                      timer->async_wait([timer, this](const boost::system::error_code& ec) {
                          std::cout << "Timer hit" << std::endl;
                      });
                      receive();
                  } else {
                      std::cout << "Error receiving data from client" << std::endl;
                  }
              });
        }
    
        io_context& ioContext;
        udp::socket localSocket_;
    };
    

    main :

    int main() {
        boost::asio::io_context ioContext;
        Proxy my_proxy(ioContext);
        my_proxy.start();
        ioContext.run();
    
        return 0;
    }