使用std :: move()移动套接字

时间:2018-11-02 19:36:50

标签: c++ sockets boost boost-asio move-semantics

我的问题与使用std::move移动Boost.Asio套接字有关。

我正在使用具有可切换实现和库(Boost.Asio,POSIX套接字,Winsock套接字)的C ++服务器。为此,我有HttpServerHttpClient接口,它们由PosixHttpServerPosixHttpClientBoostHttpServerBoostHttpClient之类的类实现。在服务器上绑定并侦听之后,HttpClient将创建HttpServer::accept()。我确保在HttpServerHttpClient上都禁止复制。我现在不打算使用异步操作。

// 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()中,如果我使用HttpClientstd::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。

0 个答案:

没有答案