Какой метод я должен использовать, чтобы узнать, какие fds открыты после разветвления процесса и затем execs - PullRequest
0 голосов
/ 04 июня 2018

Я знаю, что семейство fork и exec сохраняет дескрипторы файлов после выполнения.Такое поведение желательно для моих нужд.Также из руководства exec:

Семейство функций exec () заменяет текущий образ процесса новым образом процесса.

Итак, если я правильно понял,после того, как процесс разветвляется, а затем исполняется, программе нужны дополнительные средства, чтобы узнать, какие fds открыты.

То, что я ищу, - это простое средство передачи fds, которое будет использоваться (плюс fds, которые должны быть закрыты), чтобыновый процесс.

В качестве примечания.В Windows вы можете просто увидеть список fds, которые используются процессом.Вам нужно идти на низкий уровень, чтобы сделать это.

1 Ответ

0 голосов
/ 04 июня 2018

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

Если дочерний процесс обрабатывает только одного клиента, просто прочитайте его из его стандартного ввода (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).Это работает везде, но может быть ужасно медленным, особенно если максимальное число дескрипторов файлов велико.

...