2016-11-11 3 views
-1

Ich versuche einige Funktionstests in einigen API auszuführen.Boost.asio Client/Server TIME_WAIT warum?

Meine API hat eine Client- und eine Serverseite. Die Client-Seite verbindet und setzt eine Flagge. Der Server akzeptiert nur Verbindungen.

Dies ist ein Testfall habe ich:

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();  
    } 

Ich habe Probleme mit 2 Dinge hier:

  1. Die Verbindung ist zeitlich mehr als die Hälfte der Zeit, aber manchmal funktioniert.
  2. Beim Beenden des Programms durch den erfolgreichen Pfad bis zum Ende des Tests scheint Netstat eine Art Socket-Lecks mit dem Zustand TIME_WAIT zeigt. Ich schließe und schließe die Steckdosen. Ich kann einfach nicht herausfinden, was falsch ist.

    tcp 0 0 ip6-localhost: 52256 ip6-localhost: 54321 TIME_WAIT
    tcp 0 0 ip6-localhost: 54321 ip6-localhost: Dies wird für etwa 30-45 Sekunden, nachdem die App verlässt gezeigt 52256 TIME_WAIT

-Code für die Client- und Server-Code ist unten:

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

Der Server verarbeitet Verbindungen:

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

Warum die negativen Stimmen? –

+0

Ich sehe, dass wenn ich eine synchrone ConnectTo es funktioniert. Wenn ich eine asynchrone Verbindung zu ihm mache, funktioniert das überhaupt nicht. Aber ich verwende zwei verschiedene io_service-Schleifen in verschiedenen Threads. Obwohl ich in demselben Prozess bin, könnte das ein Problem sein? –

Antwort

2

Der TIME_WAIT-Status ist kein Sockle-Leck. Es ist ein normaler Teil der TCP-Verbindung Abbau, in RFC 793 angegeben.

+0

Dies bedeutet, dass, nachdem das Programm geschlossen und aufgeräumt ist, sollte ich das noch in Netstat als Teil des normalen Verhaltens sehen? –

+0

Was ist mit hängendem Verhalten? Warum passiert das? –

+0

@ GermánDiago: Ja, sehen Sie zum Beispiel hier: http://hea-www.harvard.edu/~fine/Tech/addrinuse.html – Matthias247