为什么这个 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
不再有效,所以我已经尝试了相关的poll
和run
功能但没有成功。
我还尝试用 boost::asio::mutable_buffer
和 boost::asio::mutable_buffer
替换 boost::asio::buffer
。然而,完全相同的代码在第一种方法中工作,所以我怀疑函数调用没问题!
根据注释 sock
,SocketManager
的 io_service
和 acceptor
成员被初始化为指向 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
成员,因为它必须在 之前 sock
和 acceptor
.
初始化
我想在一个方法中建立套接字连接,并在 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
不再有效,所以我已经尝试了相关的poll
和run
功能但没有成功。
我还尝试用 boost::asio::mutable_buffer
和 boost::asio::mutable_buffer
替换 boost::asio::buffer
。然而,完全相同的代码在第一种方法中工作,所以我怀疑函数调用没问题!
根据注释 sock
,SocketManager
的 io_service
和 acceptor
成员被初始化为指向 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
成员,因为它必须在 之前 sock
和 acceptor
.