为何Boost TCP socket在类的一个方法中正常,另一个方法报Bad file descriptor错误
问题核心原因
你出现Bad file descriptor错误的根本原因是栈局部变量生命周期误用:你将类的三个成员指针全部指向了initialize方法内部定义的栈对象,这些对象在initialize方法执行结束后就会自动析构,对应的socket、acceptor、io_service资源全部被释放,所有成员指针都变成野指针。你在evaluate方法中看到的stopped()、is_open()返回值正常,只是栈内存还未被其他数据覆盖的巧合,不代表相关对象还处于存活状态。
具体错误点:
initialize中定义的boost::asio::io_service _io_service是栈变量,方法执行结束后立即析构,成员指针io_service变成野指针- 同理
tcp::acceptor a、tcp::socket sock_都是栈变量,方法结束后析构,内部持有的文件描述符被自动关闭,这是你报错的直接原因
修复方案
你只需要将这三个对象的生命周期和类实例绑定即可,推荐两种修改方式:
方案1:使用智能指针管理堆分配对象(贴近你原有写法)
code.h修改
#include <boost/asio.hpp> #include <memory> using boost::asio::ip::tcp; class SocketManager { std::unique_ptr<boost::asio::io_service> io_service; std::unique_ptr<tcp::acceptor> acceptor; std::unique_ptr<tcp::socket> sock; public: virtual void initialize(); virtual void evaluate(); };
initialize方法修改
void SocketManager::initialize() { // 堆分配资源,生命周期和类实例绑定 io_service = std::make_unique<boost::asio::io_service>(); acceptor = std::make_unique<tcp::acceptor>(*io_service, tcp::endpoint(tcp::v4(), 1337)); sock = std::make_unique<tcp::socket>(*io_service); acceptor->accept(*sock); char data[1024]; boost::system::error_code error; size_t length = sock->read_some(boost::asio::buffer(data), error); if (error) throw boost::system::system_error(error); boost::asio::write(*sock, boost::asio::buffer(data, length)); std::cout << io_service->stopped() << std::endl; std::cout << acceptor->is_open() << std::endl; std::cout << sock->is_open() << std::endl; }
如果你的环境不支持C++14的std::make_unique,可以改用new手动分配,同时记得在类析构函数中手动delete对应指针避免内存泄漏。
方案2:直接用值类型作为类成员(更简洁,无额外内存管理成本)
code.h修改
#include <boost/asio.hpp> using boost::asio::ip::tcp; class SocketManager { boost::asio::io_service io_service; tcp::acceptor acceptor; tcp::socket sock; public: // 初始化列表构造成员对象 SocketManager() : acceptor(io_service), sock(io_service) {} virtual void initialize(); virtual void evaluate(); };
initialize方法修改
void SocketManager::initialize() { acceptor.open(tcp::v4()); acceptor.set_option(tcp::acceptor::reuse_address(true)); acceptor.bind(tcp::endpoint(tcp::v4(), 1337)); acceptor.listen(); acceptor.accept(sock); // 后续读写逻辑和原有代码一致,直接使用成员对象即可 char data[1024]; boost::system::error_code error; size_t length = sock.read_some(boost::asio::buffer(data), error); if (error) throw boost::system::system_error(error); boost::asio::write(sock, boost::asio::buffer(data, length)); std::cout << io_service.stopped() << std::endl; std::cout << acceptor.is_open() << std::endl; std::cout << sock.is_open() << std::endl; }
evaluate方法只需对应调整指针操作为值操作即可。
内容的提问来源于stack exchange,提问作者F.M.F.
相关产品推荐
相关产品推荐

