Могу ли я перенаправить stderr родительского процесса в дескриптор файла сокета на разветвленном процессе? - PullRequest
2 голосов
/ 05 января 2012

Я написал демон, который в процессе разработки передавал отладочную информацию в stderr (до того, как он был полностью 'демонизирован').Теперь код более зрелый, поэтому stderr был перенаправлен на /dev/null с вызовом freopen(2).В целях отладки я действительно хотел бы иметь возможность подключиться к демону сервера, отправить команду и волшебным образом начать отправку потока stderr через сокет.

Есть ли способ (в разветвленном процессе) выполнить операцию, подобную 'dup(2)', над stderr родительского процесса с дескриптором файла сокета-потомка? Приемлемо решение только для Linux.

Существуют большие массивы кода, которые печатаются в stderr, что - для целей проверки - я бы просто не трогал.*

Если бы dup2 мог сделать то, что я спрашиваю, это сработало бы: Перенаправить STDOUT и STDERR в сокет в C?

Ответы [ 3 ]

2 голосов
/ 05 января 2012

После того, как родительский процесс разветвился, дочерний процесс не может принудительно изменить состояние чего-либо в родительском процессе. Можно предположить, что он связывается с родителем и просит его изменить, где он пишет свой стандартный вывод ошибок, но потомок не может заставить родителя сделать это. Кроме того, если родительский элемент закрыл сокет для клиента после разветвления (что обычно происходит), он не сможет легко связаться с клиентом.

Существуют способы переноса дескриптора файла (сокета) между процессами, но я вполне уверен, что это тоже совместный процесс. Если вы хотите пойти по этому пути, то на этой странице есть описание того, что нужно сделать, и ссылки на клиентские и серверные программы для выполнения этой работы. (Требуется соединение с сокетом AF_UNIX и использование sendmsg() в дочернем демоне и recvmsg() в родительском демоне. При такой настройке дочерний демон может организовать передачу клиентского соединения сокета родительскому демону и родительскому демону Затем dup2() полученный файловый дескриптор равен 2 (стандартная ошибка), а затем закроет исходный полученный дескриптор. После этого стандартный вывод ошибок будет передан клиенту.

Это требует осторожности при настройке и (как уже говорилось) взаимодействия между дочерним и родительским процессами демона. Я на самом деле не сделал это непосредственно сам, поэтому я не уверен в подводных камнях в процессе. Я действительно знаю, что он довольно широко используется, по крайней мере, в Unix-подобных системах.

1 голос
/ 05 января 2012

Как только процесс имеет fork(2) ed, дочерний и родительский процессы не разделяют таблицы дескрипторов файлов, поэтому операции в одной из них не влияют на другую. Специфичный для Linux системный вызов clone(2) позволяет процессам совместно использовать таблицу дескрипторов файлов, используя CLONE_FILES, а информация о файловой системе (корень файловой системы, текущий рабочий каталог, umask) может быть передана в CLONE_NS. Использование clone(2) может быть слишком большим, чтобы переписать для ваших целей - и поскольку это необычно, работать с ним может быть раздражающим.

Другой подход, предложенный bmargulies , заключается в создании части «сервера ошибок» родительского процесса, которая сообщает клиентам, какой порт connect(2) предназначен для чтения информации об ошибках. Если вы придерживаетесь протокола TCP, он будет работать по сетям, но будет открыт для всех без некоторого кода аутентификации и авторизации. Если вы используете сокеты unix(7), вы можете использовать сообщения SCM_CREDENTIALS для проверки пользователя, группы и pid процесса подключения.

Вы также можете создать новый pipe(7), используя системный вызов pipe(2) для каждого дочернего элемента, до fork(2), и просто тратить файловые дескрипторы, если дочерний элемент не хотите отладочную информацию.

Если вы используете сокет unix(7) для обеспечения связи между родителем и ребенком, вы можете использовать сообщение SCM_RIGHTS для отправки дескриптора файла из одного процесса в другой - вы можете либо отправить родительский элемент pipe(7), либо socket(7) ребенку для чтения или попросите ребенка отправить родителю pipe(7) или socket(7) для письма.

1 голос
/ 05 января 2012

Что не так с dup2?

В родительском элементе, socket и connect в родительском и передать число в argv.Передайте дескриптор файла стороны записи канала потомку в argv.Затем close(2) и dup2(numberFromArgv, 2)?

Или просто передайте номер порта сервера ошибок дочернему устройству (или подключите его) и позвольте ему вызвать socket, connect и dup2.

Если подумать, держу пари, что главная проблема здесь - это часть 'f'.После вызова freopen номер дескриптора, вероятно, больше не равен «2».Позвоните fileno, чтобы получить номер, а затем используйте dup2, чтобы переместить сокет к этому номеру.

...