You need to enable JavaScript to run this app. 为何Boost TCP socket在类的一个方法中正常,另一个方法报Bad file descriptor错误
优惠活动
大模型
产品
解决方案
定价
更多

为何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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 10:30:02