如何基于已有fd创建Asio socket 数据就绪时触发自定义回调
实现方案
无需使用Asio的tcp::socket接管fd执行实际IO操作,直接使用Asio原生提供的句柄描述符类即可实现外部fd的就绪事件监听,完全适配该场景:
- POSIX兼容系统(Linux、macOS等)使用
asio::posix::stream_descriptor包装第三方API返回的socket fd - Windows平台使用
asio::windows::stream_handle包装第三方API返回的socket句柄 - 两类包装类都提供
async_wait接口,可指定监听读就绪事件,事件触发时不会自动读取fd上的数据,只会执行绑定的自定义回调,回调内可直接调用第三方API的读、解码、分发接口 - 单次
async_wait只会触发一次回调,回调执行完成后需要重新投递监听请求,才能持续接收fd的可读事件
最小实现示例
#include <asio.hpp> #include <functional> #include <system_error> class AsioFdWatcher { public: // 传入Asio io_context、第三方API持有的fd、就绪后要执行的分发回调 AsioFdWatcher(asio::io_context& ioc, int third_party_fd, std::function<void()> on_readable) : watch_fd_(ioc, third_party_fd), read_cb_(std::move(on_readable)) { start_wait_read(); } // 如需提前停止监听,调用release释放fd所有权即可,不会关闭第三方持有的fd void stop() { std::error_code ec; watch_fd_.release(ec); } private: void start_wait_read() { watch_fd_.async_wait(asio::posix::stream_descriptor::wait_read, [this](const std::error_code& ec) { if (ec) { // 此处处理fd异常、io_context退出等场景 return; } // 直接调用第三方API的读+分发逻辑,不要调用Asio的read接口操作fd read_cb_(); // 投递下一次读监听 start_wait_read(); }); } asio::posix::stream_descriptor watch_fd_; std::function<void()> read_cb_; }; /* 调用示例: int api_socket = 第三方API获取fd的接口(); AsioFdWatcher watcher( global_ioc, api_socket, []() { // 第三方API提供的 读数据->解码->分发到业务函数 的接口 third_party_api_dispatch_recv_data(); } ); global_ioc.run(); */
注意事项:
- 启用该模式后必须关闭第三方API自带的内部socket调度逻辑,不要同时用两套事件循环监听同一个fd,避免出现事件重复触发、数据被意外读取的问题
- 不要通过Asio的描述符对象调用
close()接口,fd的生命周期归第三方API管理,停止监听时调用release()释放所有权即可,避免出现重复关闭fd的错误- Windows平台只需把代码里的
asio::posix::stream_descriptor替换为asio::windows::stream_handle,其余逻辑完全一致
内容的提问来源于stack exchange,提问作者Matt Price
相关产品推荐
相关产品推荐

