【问题标题】:Why does this Boost TCP socket work in one method and not in another?为什么这个 Boost TCP 套接字在一种方法中工作而不在另一种方法中工作?
【发布时间】:2021-09-30 14:30:30
【问题描述】:

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

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

代码.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::buffer 替换为boost::asio::mutable_bufferboost::asio::mutable_buffer。但是,完全相同的代码在第一种方法中工作,所以我怀疑函数调用没问题!

【问题讨论】:

  • 不确定我是否完全理解问题,但SocketManagersockio_serviceacceptor 成员被初始化为指向SocketManager::initialize 中的局部变量。完成后,您将拥有悬空指针。
  • @G.M.这大概就是问题所在。我可以以某种方式将它们移动到实例范围吗? (我无法使用构造函数初始化它们)
  • 抱歉,刚刚看到"I cannot initialize them using a constructor" 评论。我能问为什么不吗?
  • 当我阅读您的回答时,我意识到我可以使用构造函数。请再次显示您的答案,以便我接受!非常感谢!

标签: c++ sockets boost boost-asio


【解决方案1】:

根据评论sockio_serviceacceptorSocketManager 成员被初始化为指向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 之前初始化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多