У меня есть программа, которая использует boost::asio
подключиться к удаленному компьютеру, а затем многократно распечатывать все, что он получает. Проблема в том, что всякий раз, когда я приостанавливаю его или вносю какие-либо изменения в точки останова во время его работы, возникает исключение изнутри read_until()
, Почему это происходит и что мне с этим делать?
Это на Mac под управлением OS X 10.8.2 с Xcode 4.4.1 и Apple clang 4.0. Трассировка стека от того, когда было исключение после приостановки программы:
* thread #1: tid = 0x1d07, 0x00007fff86bc9d46 libsystem_kernel.dylib`__kill + 10, stop reason = signal SIGABRT
frame #0: 0x00007fff86bc9d46 libsystem_kernel.dylib`__kill + 10
frame #1: 0x00007fff8ec40df0 libsystem_c.dylib`abort + 177
frame #2: 0x00007fff8c49ca17 libc++abi.dylib`abort_message + 257
frame #3: 0x00007fff8c49a3c6 libc++abi.dylib`default_terminate() + 28
frame #4: 0x00007fff8d05e887 libobjc.A.dylib`_objc_terminate() + 111
frame #5: 0x00007fff8c49a3f5 libc++abi.dylib`safe_handler_caller(void (*)()) + 8
frame #6: 0x00007fff8c49a450 libc++abi.dylib`std::terminate() + 16
frame #7: 0x00007fff8c49b5b7 libc++abi.dylib`__cxa_throw + 111
frame #8: 0x00000001000043df test`void boost::throw_exception<boost::system::system_error>(boost::system::system_error const&) + 111 at throw_exception.hpp:66
frame #9: 0x0000000100004304 test`boost::asio::detail::do_throw_error(boost::system::error_code const&, char const*) + 68 at throw_error.ipp:38
frame #10: 0x0000000100004272 test`boost::asio::detail::throw_error(boost::system::error_code const&, char const*) + 50 at throw_error.hpp:42
frame #11: 0x0000000100002479 test`unsigned long boost::asio::read_until<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, std::allocator<char> >(boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >&, boost::asio::basic_streambuf<std::allocator<char> >&, std::string const&) + 73 at read_until.hpp:98
frame #12: 0x00000001000012c5 test`main + 581 at main.cpp:21
frame #13: 0x00007fff8983e7e1 libdyld.dylib`start + 1
read_until()
имеет переопределение, которое вызовет исключение при ошибке, и если вы не перехватите это, то вы увидите это поведение. Если вы используете boost::asio
переопределения, которые не принимают в boost::system::error_code&
, то для безопасности вы должны обернуть эти вызовы в try
блок, который ловит const boost::system::error_code&
, В обработчике исключений вы должны изучить исключение, чтобы увидеть причину сбоя.
try
{
boost::asio::read_until(...);
}
catch(const boost::system::error_code& err)
{
// read_until(...) failed, the reason is
// contained in err
}
Когда вы приостанавливаете свою программу, фактическая пауза завершается отправкой ей сигнала POSIX (SIGSTOP
). Одним из последствий этого является то, что системные вызовы (такие как read()
, который Boost будет использовать внутренне) вернет ошибку, EINTR
, Это собирается вызвать read_until
Код обработки ошибок, который, как вы видите, выдает исключение.
Если вы хотите обрабатывать это правильно, вы, вероятно, хотите использовать перегрузку, которая принимает boost::system::error_code
параметр, проверка .value()
против EINTR
(определено в errno.h
) и повторите попытку чтения.
Это будет выглядеть примерно так
boost::system::error_code error;
boost::asio::streambuf message;
do {
boost::asio::read(socket, message, boost::asio::transfer_exactly(body_size), error);
} while (error.value() == EINTR);