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

问题描述 投票:0回答: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|

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

c++ asynchronous boost udp boost-asio
1个回答
0
投票

您正在 Proxy 类中创建一个新的

io_context
,但使用传递给套接字构造函数的那个。这种不匹配会导致问题。

固定班级:

#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;
}
© www.soinside.com 2019 - 2024. All rights reserved.