我的问题与使用std::move
移动Boost.Asio套接字有关。
我正在使用具有可切换实现和库(Boost.Asio,POSIX套接字,Winsock套接字)的C ++服务器。为此,我有HttpServer
和HttpClient
接口,它们由PosixHttpServer
,PosixHttpClient
,BoostHttpServer
,BoostHttpClient
之类的类实现。在服务器上绑定并侦听之后,HttpClient
将创建HttpServer::accept()
。我确保在HttpServer
和HttpClient
上都禁止复制。我现在不打算使用异步操作。
// main.cpp
using HttpServerPtr = std::unique_ptr<HttpServer>;
using HttpClientPtr = std::unique_ptr<HttpClient>;
...
int main(int argc, char* argv[])
{
...
//HttpServerPtr server = std::make_unique<PosixHttpServer>();
HttpServerPtr server = std::make_unique<BoostHttpServer>();
if (!server->bind(server_port)
{
...
}
if (!server->listen())
{
...
}
std::cout << "Listening to client connections at "
<< server->getAddress()
<< " on port " << std::to_string(server_port)
<< std::endl;
while (1)
{
HttpClientPtr client = server->accept();
if (!client)
{
std::cerr << "failed to accept" << std::endl;
continue;
}
std::cout << "Got connection from "
<< client->getAddress() << std::endl;
// TODO: Write HTTP response
if (!client->write("Hello World!"))
{
std::cerr << "failed to write" << std::endl;
}
}
return EXIT_SUCCESS;
}
要断开客户端套接字与HttpServer
的耦合,客户端boost::asio::ip::tcp::socket
将存储为HttpClient
的成员。在BoostHttpServer::accept()
中,如果我使用HttpClient
(std::shared_ptr
和_io_service
是{{的私有成员),则可以将Boost.Asio套接字传递到_acceptor
1}})。
HttpServer
这是我启动服务器并使用// boosthttpserver.cpp
using tcp = boost::asio::ip::tcp;
bool BoostHttpServer::bind(const uint16_t port)
{
try
{
tcp::resolver resolver(_io_service);
tcp::resolver::query query(tcp::v4(), boost::asio::ip::host_name(), std::to_string(port));
tcp::resolver::iterator available_endpoint = resolver.resolve(query);
tcp::resolver::iterator end;
for (; available_endpoint != end; ++available_endpoint)
{
tcp::endpoint localhost = *available_endpoint;
_acceptor.open(localhost.protocol());
_acceptor.bind(localhost);
_address = localhost.address().to_string();
break;
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
return false;
}
return true;
}
bool BoostHttpServer::listen()
{
try
{
_acceptor.listen();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
return false;
}
return true;
}
HttpClientPtr BoostHttpServer::accept()
{
try
{
auto client_socket = std::make_shared<tcp::socket>(_io_service);
_acceptor.accept(*client_socket);
return std::make_unique<BoostHttpClient>(client_socket);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
return nullptr;
}
}
// boosthttpclient.hpp
class BoostHttpClient : public HttpClient
{
public:
BoostHttpClient(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
BoostHttpClient(const BoostHttpClient&) = delete;
BoostHttpClient& operator=(const BoostHttpClient&) = delete;
virtual bool write(const std::string& message) override;
virtual std::string getAddress() const override;
private:
boost::asio::ip::tcp::socket _socket;
const std::string _address;
};
// boosthttpclient.cpp
BoostHttpClient::BoostHttpClient(
std::shared_ptr<boost::asio::ip::tcp::socket> socket
)
: _socket(socket)
, _address(socket->remote_endpoint().address().to_string())
{
}
时的应用程序输出:
telnet localhost 8080
但是,我想保留堆分配,在堆栈上创建Listening to connections at 127.0.0.1 on port 8080
Got connection from 127.0.0.1
并使用client_socket
将其所有权转移到BoostHttpClient
。
std::move
但是,移动后插槽不见了。好像它的析构函数被调用并被关闭了。
// boosthttpserver.cpp
using tcp = boost::asio::ip::tcp;
...
HttpClientPtr BoostHttpServer::accept()
{
try
{
tcp::socket client_socket(_io_service);
_acceptor.accept(client_socket);
return std::make_unique<BoostHttpClient>(std::move(client_socket));
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
return nullptr;
}
}
// boosthttpclient.hpp
class BoostHttpClient : public HttpClient
{
public:
BoostHttpClient(boost::asio::ip::tcp::socket&& socket);
BoostHttpClient(const BoostHttpClient&) = delete;
BoostHttpClient& operator=(const BoostHttpClient&) = delete;
virtual bool write(const std::string& message) override;
virtual std::string getAddress() const override;
private:
boost::asio::ip::tcp::socket _socket;
const std::string _address;
};
// boosthttpclient.cpp
BoostHttpClient::BoostHttpClient(boost::asio::ip::tcp::socket&& socket)
: _socket(std::move(socket))
, _address(socket.remote_endpoint().address().to_string())
{
}
我认为这和传递其他不可复制的对象(例如Listening to connections at 127.0.0.1 on port 8080
remote_endpoint: Bad file descriptor
failed to accept
或std::thread
)一样简单,就像构造函数参数一样,但是显然我不了解{{1}会发生什么}。为什么它不被转移?为什么它会自行关闭?
如果重要的话,我使用Boost 1.64.0,gcc版本7.3.1 20180712(Red Hat 7.3.1-6)和C ++ 17。