Boost.asio客户端/服务器TIME_WAIT为什么?

时间:2016-11-11 09:30:36

标签: c++ boost network-programming boost-asio

我正在尝试对某些API运行一些功能测试。

我的API有一个客户端和一个服务器端。 客户端只是连接并设置标志。服务器只接受连接。

这是我的测试案例:

BOOST_AUTO_TEST_CASE(client_can_connect_to_server) {
        boost::asio::io_service serverService;
        std::thread serverLoop([&serverService] { serverService.run(); }); 

        boost::asio::io_service clientService; 
        std::thread clientLoop([&clientService] { clientService.run(); }); 

        //    std::this_thread::sleep_for(10ms); Maybe wait for server loop to start...?


        auto connectionSuccess = connectTo("127.0.0.1", "54321", kAuthData, ioService); 

        BOOST_REQUIRE(blockForDurationOrWhile
                      (timeout,
                       [&] { return connectionSuccess.wait_for(0s) != std::future_status::ready; }) == ExitStatus::ConditionSatisfied);

        serverService.stop();
        clientLoop.join();
        serverService.join();    
    }

我在这里遇到两件事情有困难:

  1. 连接超过一半的时间超时,但有时会有效。
  2. 当通过成功路径完成程序到测试结束时,似乎netstat显示某种类型的套接字泄漏,状态为TIME_WAIT。我正在关闭并关闭插座。我只是无法弄清楚出了什么问题。应用程序退出后显示约30-45秒:

    tcp 0 0 ip6-localhost:52256 ip6-localhost:54321 TIME_WAIT
    tcp 0 0 ip6-localhost:54321 ip6-localhost:52256 TIME_WAIT

  3. 客户端和服务器代码的代码如下:

    std::future<bool> connectTo(std::string const & host,
                                std::string const & port,
                                std::string const & authData,
                                boost::asio::io_service & s,
                                std::chrono::high_resolution_clock::duration timeout = kCortexTryConnectTimeout) {
        using namespace boost::asio;
        using boost::asio::ip::tcp;
    
        std::promise<bool> p;
        auto res = p.get_future();
        spawn
            (s,
             [&s, host, port, p = std::move(p)](yield_context yield) mutable {
                tcp::socket socket(s);
                BOOST_SCOPE_EXIT(&socket) {
                    std::cout << "Closing client socket\n";
                    if (socket.is_open()) {
                        boost::system::error_code ec{};
                        socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                        socket.close();
                        std::cout << "Client socket closed\n";
                    }
                } BOOST_SCOPE_EXIT_END
    
                std::cout << "Client trying to connect\n";
                tcp::resolver resolver(s);
                boost::system::error_code ec{boost::asio::error::operation_aborted};
                boost::asio::async_connect(socket, resolver.resolve({host, port}), yield[ec]);
                std::cout << "Client Connected\n";
                if (!ec) p.set_value(true);
                else p.set_value(false);
            });
        return res;
    }
    

    服务器处理连接:

    class ConnectionsAcceptorTask {
    public:
        //Session handling for Cortex. Will move out of here
        class Session : public std::enable_shared_from_this<Session> {
        public:
            explicit Session(boost::asio::ip::tcp::socket socket) : _socket(std::move(socket)) {}
            void start() {}
    
            ~Session() {
                if (_socket.is_open()) {
                    boost::system::error_code ec{};
                    _socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    _socket.close();
                }
            }
        private:
            boost::asio::ip::tcp::socket _socket;
        };
    
        ConnectionsAcceptorTask(unsigned int port,
                                io_service & s)
            : _port(port),
              _ioService(&s)
        {}
    
        void operator()() {
            namespace ba = boost::asio;
            using boost::asio::ip::tcp;
            ba::spawn
                (*_ioService,
                 [s = _ioService, port = this->_port](ba::yield_context yield) {
    
                    tcp::acceptor acceptor
                        (*s,
                         tcp::endpoint(tcp::v4(), port));
                    acceptor.set_option(boost::asio::socket_base::reuse_address(true));
    
                    BOOST_SCOPE_EXIT(&acceptor) {
                        std::cout << "Closing acceptor\n";
                        if (acceptor.is_open()) {
                            acceptor.close();
                            std::cout << "Acceptor closed\n";
                        }
                    } BOOST_SCOPE_EXIT_END
    
                    for (;;) {
                        boost::system::error_code ec{};
                        tcp::socket socket(*s);
                        acceptor.async_accept(socket, yield[ec]); 
    
                        if (!ec) std::make_shared<Session>(std::move(socket))->start();
                    }
                });
        }
    private:
        unsigned int _port = 0;
        boost::asio::io_service * _ioService;
    };
    

1 个答案:

答案 0 :(得分:2)

TIME_WAIT状态不是套接字泄漏。它是TCP连接拆除的正常部分,在RFC 793中指定。