2016-11-11 11 views
-1

いくつかの機能テストをいくつかのAPIに実行しようとしています。Boost.asioクライアント/サーバーTIME_WAITなぜですか?

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

私はここ2、物事に問題が午前:

  1. 接続がより多くの時間の半分以上をタイムアウトし、時には動作しますが。
  2. テストの最後まで正常なパスでプログラムを終了すると、netstatは状態TIME_WAITで何らかのソケットリークを示すようです。私はソケットを閉じてシャットダウンしています。私は何が間違っているのか分かりません。

    TCP 0 0 IP6-はlocalhost:52256 IP6-はlocalhost:これはアプリが終了した後の周りの30〜45秒間表示される54321 TIME_WAIT
    TCP 0 0 IP6-はlocalhost:54321 IP6-はlocalhost:52256 TIME_WAIT

  3. クライアントとサーバーのコードの

コードは以下の通りです:

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

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

サーバーは接続を処理します

+0

なぜ否定的な票ですか? –

+0

同期ConnectToを実行すると、それが動作することがわかります。私が非同期に接続すると、全く動作しません。しかし、私は別のスレッドで2つの異なるio_serviceループを使用しています。しかし、私は同じプロセスの中にいる、それは問題になる可能性がありますか? –

答えて

2

TIME_WAIT状態はソケットリークではありません。 RFC 793で規定されているTCP接続の引き裂きの通常の部分です。

+0

これは、プログラムが閉じられてクリーンアップされた後も、通常の動作の一部としてnetstatに表示されますか? –

+0

ぶら下がり動作はどうですか?なぜそれが起こるのですか? –

+0

@GermánDiago:はい、ここをクリックしてください:http://hea-www.harvard.edu/~fine/Tech/addrinuse.html – Matthias247