Нет системного вызова, который просто дает вам список дескрипторов открытых файлов.Но большая проблема, которую вы решаете, может быть решена несколькими различными способами.Наиболее типичными являются два способа:
Если дочерний процесс обрабатывает только одного клиента, просто прочитайте его из его стандартного ввода (fd 0) и запишите в его стандартный вывод (fd 1);после разветвления, но перед освобождением, вы используете dup2
для переназначения соответствующих файловых дескрипторов на номера 0 и 1, оставляете fd 2 (stderr) в покое и закрываете все остальные (или вы заранее используете O_CLOEXEC
/ FD_CLOEXEC
, поэтомуты не обязан это делать). В некоторых Unix-системах есть удобная функция, называемая closefrom
, которая закрывает все файловые дескрипторы, числовое значение которых больше или равно его аргументу, но другие Unix-ы отказываются принимать его по причинам, которые я считаю полностью фиктивными.
Если ребенок разговаривает с сокетом или другим полнодуплексным каналом связи, заключенным в один файловый дескриптор, вы все равно должны назначить его как и fds 0 и 1, потому что таким образом stdin
и stdout
FILE объекты могут использоваться как обычно (вплоть до того момента, когда вам необходимо использовать recvfrom
, shutdown
и т. Д., В любом случае), и потому что многие библиотеки путаются, если любой из fds 0, 1,и 2 не открыты.
Эта стратегия обеспечивает хороший уровень параллелизма с минимальными усилиями и позволяет использовать дочернюю программу с inetd
и подобными такими мультиплексорами.
Еслиребенок должен обрабатывать более одного клиента, , а не назначить любого из клиентов как fds 0 или 1;вместо этого передайте разделенный запятыми список клиентских сокетов для обработки в качестве аргумента командной строки.Ребенок должен обращать внимание только на эти файловые дескрипторы и игнорировать все остальные, даже если они открыты.(Вы все равно должны приложить максимум усилий, чтобы закрыть все не относящиеся к делу fds после разветвления, но перед выпуском.)
Мультиплексирование ввода-вывода для более чем одного клиента в дочернем элементе требует гораздо большего программирования;если вам нужно пойти по этому пути, я настоятельно рекомендую использовать библиотеку асинхронного ввода-вывода, которую кто-то уже написал для вас, например libevent
или libuv
.
В обстоятельствах, когда вы действительномне нужно знать, какие fds открыты, и ваш родитель не дал вам никаких подсказок, у вас есть один плохой и непортативный вариант и один ужасный, но переносимый вариант.
Плохой и непереносимый вариант - открыть и отсканировать каталог/proc/self/fd
. Если этот каталог существует , его записи соответствуют дескрипторам открытых файлов в вашем процессе, а их имена - это десятичные числа дескрипторов.Это плохой вариант, потому что вы должны зациклить вызов readdir
и позаботиться о том, чтобы fd не поддерживал используемый вами дескриптор DIR
, и он не переносим, потому что, насколько я знаю, only Linux реализует этот специальный каталог, и он может быть недоступен даже там.
Ужасный, но переносимый вариант - запросить максимальный номер дескриптора файла с помощью getrlimit(RLIMIT_NOFILE)
, а затем выполнить цикл от 0 до этого номера, вызываяfcntl(i, F_GETFD)
, который будет возвращать неотрицательное число, если fd открыт, или отрицательное число, если оно закрыто (и для errno установлено значение EBADF).Это работает везде, но может быть ужасно медленным, особенно если максимальное число дескрипторов файлов велико.