我正在尝试使用 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|
我已经被这个问题和类似的问题困扰了几天,并且无法真正理解我做错了什么。我提取了整个代码并提炼了这个示例,希望它尽可能简洁地代表问题所在。
您正在 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;
}