Можно ли (и безопасно) сделать принимающий сокет неблокирующим?

Я ищу способ прервать вызов accept() блокирующего сокета. Использование сигналов не вариант, так как это должно быть в библиотеке, и я не хочу загромождать пользовательские сигналы. Использование select() - еще один вариант, но по разным причинам он не очень привлекателен в моем случае.

Что будет хорошо работать, если это возможно, так это установить сокет в неблокирующий режим (используя fcntl() и O_NONBLOCK) из другого потока, а сокет блокируется при вызове accept(). Ожидаемое поведение состоит в том, что вызов accept() вернется с EAGAIN или EWOULDBLOCK в errno.

Это действительно будет так работать? Это безопасно? Портативный?

Если вы знаете о применимости этого метода к Windows (где нужно использовать WSAIoctl() и FONBIO ), мне тоже интересно.


person Norswap    schedule 12.10.2012    source источник
comment
fcntl(socket, F_SETFL, O_NONBLOCK); помог мне   -  person Vlad Holubiev    schedule 30.05.2016


Ответы (2)


Понятия не имею о Windows, но желаемое поведение гарантируется POSIX:

Если очередь прослушивания пуста от запросов на соединение и O_NONBLOCK не установлен в дескрипторе файла для сокета, accept() должен блокироваться до тех пор, пока не будет установлено соединение. Если очередь listen() пуста от запросов на подключение, а в дескрипторе файла для сокета установлено значение O_NONBLOCK, accept() завершится ошибкой и установит для errno значение [EAGAIN] или [EWOULDBLOCK].

Источник: http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html

Кроме того, select или poll можно использовать для проверки входящих соединений путем опроса прослушивающего сокета в наборе для чтения.

person R.. GitHub STOP HELPING ICE    schedule 12.10.2012
comment
Вы уверены, что уже блокирующий accept() вернется, как указано, если переданный файловый дескриптор будет установлен O_NONBLOCK асинхронно? Ваша цитата кажется мне двусмысленной для данного случая. - person alk; 12.10.2012
comment
О, я неправильно понял ваш вопрос. Нет, я не думаю, что изменение режима на неблокирующий, когда он уже заблокирован, является переносимым. Почему бы вам просто не сделать его неблокирующим для начала и использовать poll или select перед вызовом accept и вызывать accept только при наличии соединения? Есть много чистых способов заставить select или poll вернуться раньше, например трюк с трубкой. - person R.. GitHub STOP HELPING ICE; 12.10.2012
comment
Итак, однозначный ответ заключается в том, что это невозможно. Как в теории, так и на практике (в итоге я попробовал это как на Linux, так и на Windows). - person Norswap; 14.10.2012
comment
В Windows вы должны использовать OVERLAPPED io. Для переносимости я бы предложил использовать Boost Asio. - person doron; 29.03.2020

В вопросе вы говорите, что не хотите использовать выбор (или опрос, или epoll), которые являются лучшими способами мультиплексирования ввода-вывода. Я бы порекомендовал вам использовать еще один поток только для прослушивания сокетов, хотя это плохая идея!

person Amir Fo    schedule 28.03.2020
comment
Спасибо за ответ, но вопрос был задан 8 лет назад. По правде говоря, я даже не помню, чего я тогда добивался! - person Norswap; 30.03.2020