У меня есть установка с сервером/клиентом, имеющими много соединений друг с другом. Данные отправляются в больших объемах. Системные вызовы select
или poll
возвращают многие файловые дескрипторы как готовые к записи. Но по мере того, как я продолжаю записывать данные, в конце концов, с N-м файловым дескриптором я получаю EAGAIN
с нулевым записанным байтом. И это продолжается по большей части.
Насколько я понимаю, это внутренний буфер ядра, который заполняется. Таким образом, остальные файловые дескрипторы не получают данных, отправляемых при пробуждении syscall
.
Мой вопрос: все ли файловые дескрипторы получают сигнал справедливо? Я имею в виду, что из общего количества файловых дескрипторов первая группа получает сигнал и перемещается в хвост доступной для записи очереди. Если нет, то как побороть вышесказанное, как сделать так, чтобы всем сокетам, которым нужна передача данных, уделялось должное внимание?
И в результате вопрос, могу ли я пропустить цикл событий, если начнет появляться EAGAIN
?
Я программирую на C, ссылки на код и пояснения приветствуются.
@AllanWind Спасибо за предложение. Я добавил теги, специфичные для ОС.
Linux не дает вам EAGAIN при заполнении справочной страницы (говорится, что это делают другие операционные системы Unix). Я ничего не знаю о FreeBSD.
@AllanWind Я не могу запустить Linux на данный момент. Глядя на справочные страницы в Интернете для Linux
, я не нашел ничего более подходящего, кроме EAGAIN
. Поэтому я разместил код ошибки для простоты чтения.
Вы отметили свой вопрос linux, поэтому я упомянул об этом. Из select(2) «В некоторых других UNIX-системах select() может завершиться ошибкой EAGAIN, если системе не удается выделить внутренние ресурсы ядра, а не ENOMEM, как это делает Linux. POSIX указывает эту ошибку для poll(2), но не для select(). Переносимые программы могут захотеть проверить наличие EAGAIN и цикла, как и в случае с EINTR."
Мой вопрос: все ли файловые дескрипторы получают сигнал справедливо?
И poll
, и select
вернут информацию о том, какие дескрипторы файлов в настоящее время доступны для чтения/записи на момент возврата вызова. Это «справедливо» в том смысле, что все они указаны одновременно. Вам нужно будет перебрать все дескрипторы и записать каждый из них, который доступен для записи. Вы можете предпочесть одни из них другим, если хотите, или сделать свою петлю более справедливой.
Когда вы write
переходите к дескриптору, он возвращает EAGAIN
или EWOULDBLOCK
для любого неблокирующего и не имеющего буферного пространства. Каждый fd имеет свой собственный буфер, так что это, происходящее в одном fd, не имеет никакого отношения к каким-либо другим fd, и они все еще могут быть доступны для записи.
Думаю, нужно больше тестировать ситуацию в реальных приложениях. Вернемся к вопросу через некоторое время.
Я бы ожидал поведения FIFO и того, что вы хотите обработать любые файловые дескрипторы, готовые до повторения цикла событий.