Так что для аспекта перенаправления вам нужно использовать dup2 () в ответвлении файловых дескрипторов.Чтобы настроить трубу, вам нужно использовать pipe () в главном потоке, чтобы создать дескрипторы, которые вы затем будете dup2 () внутри вилки.
Обратите внимание, что вы должны быть очень осторожны, чтобы pipe ()не дает вам дескриптор файла с низким номером.Вы можете использовать fcntrl (F_DUPFD, ...), чтобы запугивать их до больших чисел.Кроме того, используйте CLOEXEC, чтобы избавиться от всех вторичных дескрипторов мусора, плавающих вокруг.
Псевдокод:
fin = open("input", read)
pipeIO = pipe()
fout = open("output", write)
fin2 = fcntrl(F_DUPFD_CLOEXEC, fin, 3); close fin
pipeI2 = fcntrl(F_DUPFD_CLOEXEC, pipeI, 3); close pipeI
pipeO2 = fcntrl(F_DUPFD_CLOEXEC, pipeO, 3); close pipeO
fout2 = fcntrl(F_DUPFD_CLOEXEC, fout, 3); close fout
fork
{
dup(fin2, 0)
dup(pipeO2, 1)
exec Command1
}
close fin2
close pipeO2
fork
{
dup(pipeI2, 0)
dup(out2, 1)
exec Command2
}
close fout2
close pipeI2
wait
В качестве альтернативы, вторая ветвь может цепочкой-exec:
Псевдокод:
fin = open("input", read)
pipeIO = pipe()
fout = open("output", write)
fin2 = fcntrl(F_DUPFD_CLOEXEC, fin, 3); close fin
pipeI2 = fcntrl(F_DUPFD_CLOEXEC, pipeI, 3); close pipeI
pipeO2 = fcntrl(F_DUPFD_CLOEXEC, pipeO, 3); close pipeO
fout2 = fcntrl(F_DUPFD_CLOEXEC, fout, 3); close fout
fork
{
dup(fin2, 0)
dup(pipeO2, 1)
exec Command1
}
dup(pipeI2, 0)
dup(out2, 1)
exec Command2
Вы уже ясно знаете, что когда вы выполняете разветвление, дочерний процесс фактически дублирует все дескрипторы, и в тот момент, когда код фактически выполняется, должна быть открыта только одна версия.Родитель или дочерний элемент должны закрывать каждый дескриптор, который ему не интересен. Используя CLOEXEC, мы уменьшаем эту потребность, хотя, если вы хотите сохранить родительский процесс в качестве монитора, ему необходимо закрыть все свои копии всех этих дескрипторов..
Краткое описание функций dup:
0 = pipe (handle [2])
Это создает пару дескрипторов, которые присоединяются друг к другу в качестве входа и выхода.Классически вы можете связываться с вилкой одним процессом, записывая в один дескриптор вилки, а другой процесс считывая другой дескриптор, в зависимости от того, каким образом вы хотите их использовать.В этом случае мы используем канал для связи между двумя дочерними процессами, а родительский не задействован.
handle = dup (handle)
Создает дублирующий дескриптор в самом низком неиспользуемом слоте.Если ваша программа закрыла stdin / stdout / stderr, она будет использовать те, которые будут проблематичными.Также эти дескрипторы остаются активными в вызовах exec.
handle = dup2 (handle, trghandle)
Это создает дублирующий дескриптор по указанному вами индексу.Он будет молча закрывать любое существующее использование trghandle, что может быть как полезным, так и раздражающим!
handle = dup3 (handle, trghandle, flags)
Это создает дублирующий дескриптор по указанному вами индексу.Это молча закроет любое существующее использование trghandle, которое может быть и полезным и раздражающим!Вы можете указать флаги, такие как CLOEXEC, который автоматически закрывает дескриптор при вызове exec.CLOEXEC действительно полезен во избежание необходимости явно закрывать файлы.
int fcntl (int fd, int cmd, ... / * arg * /);
F_DUPFD (int) Дублируйте дескриптор файла fd, используядескриптор файла с наименьшим номером больше или равен аргументу.
F_DUPFD_CLOEXEC (int; начиная с Linux 2.6.24) Как и в случае F_DUPFD, но дополнительно установите флаг закрытия при выполнении для дескриптора дубликата файла.
... что позволяет легко избежать стандартного ввода / вывода.