2016-11-11 96 views
-1

我想在一些API中運行一些功能測試。Boost.asio客戶端/服務器TIME_WAIT爲什麼?

我的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-本地主機:52256的IP6-本地主機:54321 TIME_WAIT
    TCP 0 0 IP6-本地主機:54321的IP6-本地主機:52256 TIME_WAIT

代碼客戶端和服務器的代碼如下:

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; 
}; 
+0

爲什麼是負面投票? –

+0

我看到,當我做一個同步ConnectTo它的作品。當我進行異步連接時,根本不起作用。但是我在不同的線程中使用了兩個不同的io_service循環。雖然,我在同一個過程中,這可能是一個問題嗎? –

回答

2

TIME_WAIT狀態不是套接字泄漏。它是TCP連接拆除的正常部分,在RFC 793中有詳細說明。

+0

這意味着,在程序關閉並清理之後,我仍然應該將netstat視爲正常行爲的一部分? –

+0

懸掛行爲呢?爲什麼會發生? –

+0

@GermánDiago:是的,例如在這裏看到:http://hea-www.harvard.edu/~fine/Tech/addrinuse.html – Matthias247