为什么这个 Boost TCP 套接字在一种方法中工作而不在另一种方法中工作?

Why does this Boost TCP socket work in one method and not in another?

我想在一个方法中建立套接字连接,并在 class 的另一个方法中使用此连接。在第一种方法(我建立连接的地方)中,我可以根据需要从套接字读取和写入套接字,而在第二种方法中,我总是得到 Bad file descriptor 错误。 请注意,我使用的是 1.65.1 版本的 Boost。

我创建了一个可重现的小示例(我添加了一些日志以进行说明):

code.h

#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class SocketManager {
    tcp::socket *sock;
    boost::asio::io_service *io_service;
    tcp::acceptor *acceptor;

    public:
        virtual void initialize();  // works
        virtual void evaluate();  // fails
};

code.cc

#include "code.h"
#include <iostream>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using namespace std;


int main() {
    SocketManager sm;
    sm.initialize();
    sm.evaluate();
    return 0;
}

void SocketManager::initialize() {
    boost::asio::io_service _io_service;
    io_service = &_io_service;

    tcp::acceptor a(*io_service, tcp::endpoint(tcp::v4(), 1337));
    acceptor = &a;

    tcp::socket sock_(*io_service);
    sock = &sock_;

    a.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);  // No Error here!

    boost::asio::write(*sock, boost::asio::buffer(data, length));

    cout << io_service->stopped() << endl;  // prints 0
    cout << acceptor->is_open() << endl;  // prints 1
    cout << sock->is_open() << endl;  // prints 1
}

void SocketManager::evaluate() {
    cout << io_service->stopped() << endl;  // prints 0
    cout << acceptor->is_open() << endl;  // prints 1
    cout << sock->is_open() << endl;  // prints 1

    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);  // Error: "Bad file descriptor"
}

以上代码与客户端一起使用时的输出:

root@5531547d4baf:/cpp# ./a.out 
0
1
1
0
1
1
terminate called after throwing an instance of 'boost::system::system_error'
  what():  Bad file descriptor
Aborted

请注意,抛出错误的代码在两种方法中是完全相同的代码(在第一个方法中,它可以正常工作,而在第二个方法中,它会抛出 Bad file descriptor 错误)。

我怀疑切换到新功能时io_service不再有效,所以我已经尝试了相关的pollrun功能但没有成功。

我还尝试用 boost::asio::mutable_bufferboost::asio::mutable_buffer 替换 boost::asio::buffer。然而,完全相同的代码在第一种方法中工作,所以我怀疑函数调用没问题!

根据注释 sockSocketManagerio_serviceacceptor 成员被初始化为指向 SocketManager::initialize 中的局部变量。完成后,您就会有悬空指针。

我看不出有任何理由在这里使用指针。只需将它们设为非指针数据成员并在构造函数中初始化它们(未测试)...

class SocketManager {
    boost::asio::io_service io_service;
    tcp::acceptor           acceptor;
    tcp::socket             sock;
public:
    SocketManager ()
      : acceptor(io_service, tcp::endpoint(tcp::v4(), 1337))
      , sock(io_service)
      {}
      ...
};

请注意,首先声明 io_service 成员,因为它必须在 之前 sockacceptor.

初始化