2016-05-26 21 views
9

Mam serwer TCP na boost :: asio, nasłuchuje połączenia i po jego uruchomieniu rozpoczyna wysyłanie bloków danych za pomocą instrukcji boost :: asio :: write w pętli.Nie można złapać wyjątku z boost :: asio :: io_service :: uruchom

bool TcpServer::StartTcpServer(std::shared_ptr<boost::asio::io_service> io_service) 
{ 
    m_ioservice = io_service; 
    m_acceptor.reset(new boost::asio::ip::tcp::acceptor(*m_ioservice, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), m_port))); 
    m_socket = std::unique_ptr<boost::asio::ip::tcp::socket>(new boost::asio::ip::tcp::socket(*m_ioservice)); 

    m_socket->close(); 
    m_acceptor->async_accept(*m_socket, m_peer_endpoint, boost::bind(&TcpServer::AcceptHandler, this, boost::asio::placeholders::error)); 

    m_io_thread.reset(new std::thread([this]{ 
    try 
    { 
     this->m_ioservice->run(); 
    } 
    catch(const boost::system::system_error & err){print logs} 
    catch(...){print another logs} 
    })); 
} 

void TcpServer::AcceptHandler(const boost::system::error_code &ec) 
{ 
    while(true) 
    { 
     try 
     { 
      boost::asio::write(*m_socket, boost::asio::buffer(data->c_str(), data->size()), boost::asio::transfer_all()); 
     } 
     catch(const boost::system::system_error & err){print logs} 
     catch(...){print another logs} 
    } 
} 

Jeśli ręcznie zatrzymam odbiornik, wyjątek dotyczący uszkodzonego przewodu jest generowany i obsługiwany prawidłowo. Ale rura czasami łamane dzieje (przyczynę złego połączenia ja przypuszczam) i wyjątek cudownie spada przez wszystkich połowów, a aplikacja jest rozwiązana:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >' 

Badanie rdzeń widzę, że to się stało w boost :: asio :: write pochodzi z io_service :: run(). Co ja robię źle?

Próbowałem również przepisać serwer TCP za pomocą async_write, ale nadal tak się dzieje, ale nie tak często.

EDIT1: jeśli zatrzymam odbiornik ręcznie powodując uszkodzenie rury, otrzymam dokładnie ten sam wyjątek i dokładnie taki sam odbiór, ale ten, który mogę obsłużyć.

EDIT2: z tego, co rozumiem, teraz wyjątek, którego nie można odczytać, może być wynikiem zbyt dużej ilości danych wysyłanych zbyt szybko przez gniazdo. Nie jestem tego pewien.

+0

Czy jesteś pewien, że jest to wyjątek? Co otrzymasz, jeśli "złapiesz (...)"? – wally

+0

Mam wydruk z napisem "zakończ wywołanie po rzuceniu instancji" boost :: wyjątek_detail :: clone_impl > ' what(): write: Broken pipe ". złapać (...) niczego nie łapie. –

+0

Czy to jest rzucanie z jakiejś funkcji, która ma specyfikację wyjątku? Spójrz na [tę odpowiedź] (http://stackoverflow.com/a/26332289/1460794). – wally

Odpowiedz

1

Komunikat o błędzie w terminate faktycznie wyjaśnia, co się dzieje. boost::exception_detail::clone_impl kończy się niepowodzeniem. Bez przekopywania się przez kod, zakładam, że jest on używany do implementacji konstruktora kopii klasy wyjątków. Jeśli ten konstruktor kopiowania zgłasza wyjątek podczas obsługi wyjątków, ominie blok wyjątku, a wyjątek będzie propagowany w górę. (Nawet jeśli złapiesz przez referencję, kopie nadal mogą być tworzone przez kompilator.)

Teraz nie wiem dlaczego Konstruktor kopiowania nie działa; nie ma wystarczającej ilości informacji na ten temat. Ale this question odnoszące się do asynchronicznego I/O miał bardzo podobny problem, a sedno wydaje się, że shared_ptr został zniszczony przed przetwarzaniem wyjątków. Wygląda podobnie.

Powiązane problemy