LINUX.ORG.RU

вернуть бы управление из boost::asio::ip::tcp::acceptor::accept()

 


0

2

Товарищи, помогите, уже не знаю, что тут можно сделать. Имею TCP соединение и boost::asio для работы с ним. Жду клиента на подключение с помощью метода

boost::asio::ip::tcp::acceptor::accept()
Проблема в том, что при выходе из программы хорошо бы вернуть управление из этой функции. Как это сделать - не знаю. Accept конечно же висит в отдельном потоке и временно сделан костыль в виде
boost::thread::interrupt()
но очень бы хотелось по-человечески с помощью
boost::thread::join()
Для возврата управления у акцептора есть два метода - close() и cancel().

Один и тот же код компилировался под двумя операционными системами.

Под виндой cancel вываливает ошибку, мол не поддерживается этот метод для данного типа сокета, однако close() возвращает управление из accept().

Под линуксом cancel() ошибок не выдает и ничего не делает, а close() выдает bad file descriptor и управление из accept() не возвращается.

Асинхронные сокеты не предлагать. Нужную железяку для тестирования трудно достать, а текущее синхронное соединение уже проверено.

Это баг или существуют другие способы возврата управления из синхронного акцептора под линуксом?


Ответ на: комментарий от four_str_sam

Не совсем понял, а чем это поможет? В процессе работы программы мне нужно ловить того, кто хочет подключиться. Есть соединения или нет - все равно нужно ждать клиента.

Burns
() автор топика

Что-то толковых ответов нет. В общем гугл говорит юзай асинхронные сокеты, все примеры на них. Либо разбирайся, как работает этот asio и на низком уровне (с помощью сигналов ОС) отрубай свой accept. Да, причиной этого сообщения стал сайт

http://mo.morsi.org/blog/node/273

с вконец опечаливающей строкой:

It is impossible to cancel synchronous operations

Но все же я не один такой, кто использует синхронный boost::asio::tcp. Оставлю тему пока открытой, может еще кто-нибудь что-нибудь предложит.

Burns
() автор топика
Ответ на: комментарий от placement_new

Установи сам соединение из другого потока и отправь 'fuck off' :)

хаха))) Очень интересное решение, почему-то о нем даже и не подумал. Но все же это некий костыль, который, если уж по-честному не совсем правильный, поэтому пока что оставлю как есть, но большое спасибо, теперь я знаю, что можно сделать с синхронными сокетами)).

В общем я решил оставить задачу в таком виде:

#ifdef WINDOWS_VERSION
  _thread.join();
#else
  _thread.interrupt();
#endif
Выяснил еще такой факт, если не вызывать acceptor::close() и сразу рубить поток thread::interrupt(), то гарантированно получишь исключение, которое не отловить, оно вываливает программу (кстати, как такие исключения называют?). Однако, если вызвать acceptor::close(), то появление этого исключения после thread::interrupt() появляется негарантированно. На Ubuntu 14.04 оно вылетает через раз. На другой ОС (хз че там, что-то GNU/Linux подобное) я это исключение не получил ни разу. Интересно, почему так происходит, но чтобы разобраться, нужно копать недры буста, что не очень то и охота. Если часто начнет появляться это исключение, заменю, как Вы и предложили, еще раз огромное спасибо))

Burns
() автор топика
Ответ на: комментарий от Burns

Ты close из другого потока что ли вызываешь? На сколько я помню boost, ip::tcp::acceptor помечен non-thread-safe...

А исключение скорей всего кидается потому что accept возвращает -1, так как ты закрыл сокет из другого потока. Стремно вообщем как то все...

placement_new ★★
()
Последнее исправление: placement_new (всего исправлений: 2)
Ответ на: комментарий от placement_new

Потокобезопасность это не проблема. Мьютаксами пользоваться я умею =).

Исключение кидаться не должно, т.к. я передаю в accept объект boost::error. В теории все исключения должны прекратить кидаться и записываться в виде ошибки в boost::error, хотя возможно есть нюансы

Burns
() автор топика
Ответ на: комментарий от Burns

А как тебе мьютекс поможет? У тебя же поток, который accept делает, он же блокируется на accept, значит ты либо мьютекс не захватил, либо не освободил здесь. Может проще accept сделать с timeout и проверять каждый раз не пора ли завершиться.

placement_new ★★
()
Последнее исправление: placement_new (всего исправлений: 1)
Ответ на: комментарий от placement_new

а к accept можно прилепить timeout? Как, как, как??? В свободное время конечно еще раз перечитаю http://habrahabr.ru/post/192284/ с акцентом на accept, но после последнего беглого прочтения не помню, чтобы упоминалась возможность ввести timeout

Burns
() автор топика
Ответ на: комментарий от placement_new

Сокет то засунуть можно, если он обычный, созданный функцией socket(). Тут и бороться особо вроде не с чем, достаточно вызвать close(socketDescriptor) и все будет завершаться без проблем.

Однако тут я вопрос поставил относительно буста. Где у буста хранится дескриптор сокета я не знаю и нет времени на его поиски. Возможно, просто необходимо изменить опции сокета и он отрубится без проблем, не знаю, вот и ищу умные мысли

Burns
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.