Доброго времени суток!Вот тут странноя штука вышла с пайпом - написал простенькое перенаправление вывода, причем работает :) но, прихорашивая текст, обнаружил странность.
В общем, создаю два пайпа и два потомка, у потомка stdin назначаю на pipe[0], stdout - на файл, который в потомке и создается. Вот эта функция работает после форка для потомка.
int run_child(char *output_file, int *fd)
{
int out;
int c;dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);if(-1 != (out = open(output_file, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE))){
dup2(out, 1);
close(out);execlp("cat", "cat", NULL);
}exit(0);
return 0;
}Родитель для каждого потомка пишет сообщение в пайп, закрывает дескрипторы и ждет завершения потомков.
for(i = 0; i < 2; i++){
if(0 > (task[i].pid = fork())){
printf("Fork error !\n");
exit(2);
}
if(task[i].pid == 0)
run_child(output_file[i], task[i].fd);
/************************* Здесь пишем ***********/
close(task[i].fd[0]);
write(task[i].fd[1], big_string, strlen(big_string));
close(task[i].fd[1]);
/*************************************************/
}for(i = 0; i < 2; i++) /* waitpid(task[i].pid, &task[i].status, 0);
Все чудненько, строка уходит в соответствующий файл, Но если вынести запись в пайп из цикла(выделенный блок), то есть сначала создать всех потомков, а потом чего-то им послать, то начинаются странности: файлы либо нулевые, либо длиной 4096(зависит от размера строки-сообщения),
родитель намнртво встает на waitpid().Программка махонькая, здесь она почти вся.
В принципе, она в таком вот виде работает, но я понимаю, что что-то упускаю. Вроде, по книжке делал :)В общем, сам не пойму, а где еще найти таких гуру как здесь - не знаю.
Помогите, плиз, разобраться,
Зря ты кусок обрезал. Так и не поймешь что, как и куда ты выносишь. Весь код в студию.
>Зря ты кусок обрезал. Так и не поймешь что, как и куда
>ты выносишь. Весь код в студию.Вот, пожалуйста. При пересылке почему-то теряются отступы, смотреть страшно:)
/********************Начало**************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>char *output_file[] = {"out1", "out2"};
struct {
int pid;
int status;
int fd[2];
} task[2];#define BIG_SIZE 5000
char big_string[BIG_SIZE];
int run_child(char *output, int *fd)
{
int out;
int c;dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);if(-1 != (out = open(output, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE))){
dup2(out, 1);
close(out);execlp("cat", "cat", NULL);
}exit(0);
return 0;
}main()
{
int i;for(i = 0; i < BIG_SIZE; i++)
big_string[i] = 'a';
for(i = 0; i < 2; i++)
if(pipe(task[i].fd) < 0){
printf("Pipe error\n");
exit(1);
}
for(i = 0; i < 2; i++){
if(0 > (task[i].pid = fork())){
printf("Fork error !\n");
exit(2);
}
if(task[i].pid == 0)
run_child(output_file[i], task[i].fd);
/**********Когда пишу здесь, то работает************************
close(task[i].fd[0]);
write(task[i].fd[1], big_string, BIG_SIZE);
close(task[i].fd[1]);
*******************************************/
}/**************Если пишу здесь, то не работает********/
for(i = 0; i < 2; i++){
close(task[i].fd[0]);
write(task[i].fd[1], big_string, BIG_SIZE);
close(task[i].fd[1]);
}
/******************************************/
for(i = 0; i < 2; i++)
waitpid(task[i].pid, &task[i].status, 0);return 0;
}
/****************Конец***********************/$uname -a
Linux localhost.localdomain 2.4.3-20mdk #1 Sun Apr 15 23:03:10 CEST 2001 i686 unknown
>При пересылке почему-то теряются отступы, смотреть страшно:)
bash$ sed -e 's/\t/ /g' prog.c
>>При пересылке почему-то теряются отступы, смотреть страшно:)
>bash$ sed -e 's/\t/ /g' prog.cCпасибо. Мне бы вот еще с пайпами разобраться :)
>>>При пересылке почему-то теряются отступы, смотреть страшно:)
>>bash$ sed -e 's/\t/ /g' prog.c
>
>Cпасибо. Мне бы вот еще с пайпами разобраться :)
Я просмотрел бегло (на большее нет времени). Вроде, много ошибок разных.
Во-первых, exec() заменяет на cat, а тот cat закроет файл или нет по умре?
Думаю, что закроет, если работает. Лучше, наверное, передать имя файла
cat, а не открывать его. Если это только тест, то стоит заменить exec() на
ручную запись.
Все write() написаны не аккуратно: нет проверок ошибок, write() не обязан
записывать все данные за один раз. 5000 скорее всего больше вместимости
канала (по POSIX -- не менее 512, но во всех системах поразному).
4096 -- это чай поди вместимость канала. Умозрительно (уточнять некогда),
дедлок получается когда родитель пишет в канал, переполняя его, а потомок
не успевает прочитать, освободив; но я не уверен. Проверить эту гипотезу
просто: нужно заменить 5000 на 512.
>Во-первых, exec() заменяет на cat, а тот cat закроет файл или нет
>по умре?
>Думаю, что закроет, если работает. Лучше, наверное, передать имя файла
>cat, а не открывать его. Если это только тест, то стоит заменить
>exec() на
>ручную запись.Мне надо было именно перенаправить stdout а не просто распечатать что-то.
Я так понимаю, свой stdout процесс по окончании работы закроет обязательно.>Все write() написаны не аккуратно: нет проверок ошибок, write() не обязан
>записывать все данные за один раз. 5000 скорее всего больше вместимости
>канала (по POSIX -- не менее 512, но во всех системах поразному).Неаккуратно, да. Просто это не профессиональное приложение, Так, демонстрашка возможностей UNIX :)
>4096 -- это чай поди вместимость канала. Умозрительно (уточнять некогда),
Да, так в мануалах и написано. Поэтому я писал больше 4096 байт.
Насчет write() и 512 байт... Так что же, выходит, каждый раз после отктытия файла в UNIX надо проверять, не пайп ли это? Обычно в файл пишут, не задумываясь о размерах записываемого(ну, в разумных пределах)
и проверяют, сколько записалось. А так выходит, что при записи более 512 байт можно нарваться на деадлок, если файл вдруг трубой оказался.
>Мне надо было именно перенаправить stdout а не просто распечатать что-то.
>Я так понимаю, свой stdout процесс по окончании работы закроет
>обязательно.
Надо бы проверить, но думаю, что проблем нет.>>Все write() написаны не аккуратно: нет проверок ошибок, write() не обязан
>>записывать все данные за один раз. 5000 скорее всего больше вместимости
>>канала (по POSIX -- не менее 512, но во всех системах поразному).
>
>Неаккуратно, да. Просто это не профессиональное приложение, Так,
>демонстрашка возможностей UNIX :)
Тут write() -- самое интересное место, как я подозреваю. Потом, проверки
для read()/write() нужно привыкнуть писать на автомате (хорошо проверенная
рекомендация).>Насчет write() и 512 байт... Так что же, выходит, каждый раз после
>отктытия файла в UNIX надо проверять, не пайп ли это? Обычно
>в файл пишут, не задумываясь о размерах записываемого(ну, в разумных пределах)
>
>и проверяют, сколько записалось. А так выходит, что при записи более 512
>байт можно нарваться на деадлок, если файл вдруг трубой оказался.
Труба и файл -- вещи принципиально разные. Это интерфейс намеренно сделан
одинаковым, семантика существенно разная. Если пишем в канал, то
подразумеваем, что на другом конце кто-то есть и он уже читает, ну разве
что он призапоздал и вот-вот начнёт читать (запоздание порядка времени
старта нового процесса). Но если тот читатель гикнулся, то кердык, так
сказать, -- наше предположение сильно не точно, ибо вместимость канала
очень маленькая, а read()/write() по умолчанию будут ждать у моря погоды.
512 байт не есть причина дедлока. Причина в том, что у трубы два конца, и
читателю нужен писатель (писателю не нужен читатель, вплоть до
переполнения канала). Если читатель висит в read(), то писатель висит в
waitpid() (похоже так тут и есть; это значит, что write() не сработал).
512 байт связано с другой проблемой: если в один и тот же канал пишут
двое, то как перемешаются их данные?Если я правильно понял задачу, есть один писатель и два читателя,
которые должны сбрасывать данные в файлы. Читатели должны использовать
какие-то фильтры, читающие из stdin и пишущие в stdout. Вопрос: как
организовать надёжный обмен данными? Думается, достаточно проверять
успешность write() при записи в канал.Кстати, я так и не удосужился пощупать этот код. Писатель виснет в
waitpid(). А что делают читатели (оба)?
>>Неаккуратно, да. Просто это не профессиональное приложение, Так,
>>демонстрашка возможностей UNIX :)
>Тут write() -- самое интересное место, как я подозреваю. Потом, проверки
>для read()/write() нужно привыкнуть писать на автомате (хорошо проверенная
>рекомендация).
Да, конечно. В рабочей задаче я делаю всякие проверки, а тут - если все проверять, в экран не влазит :)>Труба и файл -- вещи принципиально разные. Это интерфейс намеренно сделан
>одинаковым, семантика существенно разная. Если пишем в канал, то
>подразумеваем, что на другом конце кто-то есть и он уже читает, ну
>разве
>что он призапоздал и вот-вот начнёт читать (запоздание порядка времени
>старта нового процесса). Но если тот читатель гикнулся, то кердык, так
>сказать, -- наше предположение сильно не точно, ибо вместимость канала
>очень маленькая, а read()/write() по умолчанию будут ждать у моря погоды.
>512 байт не есть причина дедлока. Причина в том, что у трубы
>два конца, и
>читателю нужен писатель (писателю не нужен читатель, вплоть до
>переполнения канала). Если читатель висит в read(), то писатель висит в
>waitpid() (похоже так тут и есть; это значит, что write() не сработал).
>
>512 байт связано с другой проблемой: если в один и тот же
>канал пишут
>двое, то как перемешаются их данные?
Наверное, будет зависеть от того, как сбрасываются буфера(например, с помощью fflush()).>Если я правильно понял задачу, есть один писатель и два читателя,
>которые должны сбрасывать данные в файлы. Читатели должны использовать
>какие-то фильтры, читающие из stdin и пишущие в stdout. Вопрос: как
>организовать надёжный обмен данными? Думается, достаточно проверять
>успешность write() при записи в канал.
Мне надо было запустить кучку процессов, а их stdout поместить в файлы.
В принципе, все бы могло сделаться через
system("taskNN < inputNN > outputNN");
но это должно запускать копию shell и быть более громоздким.
Поэтому я использовал трюки с форком и пайпом. Как я уже говорил, случайно я нашел сначала "рабочий" вариант и применил его. Но вопрос остался :)>Кстати, я так и не удосужился пощупать этот код. Писатель виснет в
>
>waitpid(). А что делают читатели (оба)?
strace говорит, что они виснут на read(). Вроде как конца файла нет.В общем, я нашел, где я был серьезно неправ. Я же создал две трубы, и для каждого потомка остается кроме рабочей трубы еще и труба, предназначенная для другого потомка. По хорошему, ее тоже надо закрывать.
Когда я стал закрывать другую трубу, все заработало.
Вообще говоря, у меня сложилось впечатление, что в разных юниксах
можно нарваться на разные неожиданности с тем же пайпом :)
Хотя я, конечно, понимаю, что эти мои проблемы - просто от недостатка соответствующего опыта.
Try this, this code works OK:http://www.advancedlinuxprogramming.com/listings/chapter-5/p...
http://www.advancedlinuxprogramming.com/listings/chapter-5/d...Good luck!
как то недавно уже была некоторая тема с "advanced...",
и всё-равно ещё раз упомяну : ВСЕ примеры в книге (то есть ни один из них) не могут быть использованны без существенной доработки, они лишь демонстрируют общий принцип. Видимо и писались с такой целью, чтобы их нельзя было без риска использовать..
>как то недавно уже была некоторая тема с "advanced...",
>и всё-равно ещё раз упомяну : ВСЕ примеры в книге (то есть
>ни один из них) не могут быть использованны без существенной доработки,
>они лишь демонстрируют общий принцип. Видимо и писались с такой целью,
>чтобы их нельзя было без риска использовать..
Что указывает на низкое качество изложения.
По крайней мере, тонкие места обязательно должны быть выделены, если их
устранение оставляется читателю в качестве упражнения. Ещё и начало с основ
набора текста в Emacs подразумевает особый уровень изложения, так сказать,
для тех, кто хочет разобраться в вещах "само собой разумеющихся".
Но, для начинающих писать на C (а не на C++) для Linux книга эта весьма
полезна, по моему разумению.
>Try this, this code works OK:
>
>http://www.advancedlinuxprogramming.com/listings/chapter-5/p...
>http://www.advancedlinuxprogramming.com/listings/chapter-5/d...
>
>Good luck!
Спасибо, полезный сайт.
В принципе, я вроде разобрался (ответ для SergeyZz).
Кстати, вопрос: нет ли где фри шелла на неинтеловской архитектуре? То есть, конечно, их много, но я не знаю бесплатного :) Скажем, для тестов мне удобно иногда пользоваться cyberspace.org - там OpenBSD с простой процедурой регистрации. Но хотелось бы неинтел. Привычка к интеловскому порядку байт иногда подводит :)
Всем привет помогите плиз с моей трабл, немогу разобраться в чес дело
я пытаюсь перенаправить вывод данных с программы исполняемой в execlp
но в буфер однозначно ничего не выводит, никак не могу понять почему
вот исходник может есть соображения :#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
int main()
{
pid_t pid;
pid_t pido;
int pip[2];
char buffer[255] = "empty";
int status,died;
switch(fork())
{
case -1 :
printf("%s","Error fork \n");
return EXIT_FAILURE;
case 0:
printf("%s","Run pid OMStip\n");
pipe(pip);
close(0);
dup2(pip[1],1);
close(pip[0]);
close(0);
pid = execlp("/local/mms-v20/lib/linux_v9/OMStip","OMStip","T75","-done","wan0",0);
read(pid,buffer,255);
close(pid);
close(pip[0]);
close(pip[1]);
_exit(pip[1]);
}
printf("out : \n");
printf("%s\n",buffer);
close(0);
close(pip[0]);
close(pip[1]);
close(pid);
return EXIT_SUCCESS;
}
> pid = execlp("/local/mms-v20/lib/linux_v9/OMStip","OMStip","T75","-done","wan0",0);
> read(pid,buffer,255);Если мне не изменяет память, то ф-ции из семейства exec управление не возвращают, иными словами ваш read() даже не выполнится. Вам, видимо, нужно использовать popen().
>> pid = execlp("/local/mms-v20/lib/linux_v9/OMStip","OMStip","T75","-done","wan0",0);
>> read(pid,buffer,255);
>
>Если мне не изменяет память, то ф-ции из семейства exec управление не
>возвращают, иными словами ваш read() даже не выполнится. Вам, видимо, нужно
>использовать popen().FILE *pid = popen("/local/mms-v20/lib/linux_v9/OMStip T75 -done wan0","r");
read(pid,buffer,255);
получается надыть так?
>FILE *pid = popen("/local/mms-v20/lib/linux_v9/OMStip T75 -done wan0","r");
> read(pid,buffer,255);
>получается надыть так?Не совсем так, потому что popen() возвращает FILE *, а read() ждёт int в качестве файлового дескриптора. Так что вам, по-видимому, нужно fread() использовать.
P.S. Почитайте маны)
>>FILE *pid = popen("/local/mms-v20/lib/linux_v9/OMStip T75 -done wan0","r");
>> read(pid,buffer,255);
>>получается надыть так?
>
>Не совсем так, потому что popen() возвращает FILE *, а read() ждёт
>int в качестве файлового дескриптора. Так что вам, по-видимому, нужно fread()
>использовать.
>
>
>P.S. Почитайте маны)Угу уже поитал уже разобрался всем спасиб =) терь тока надо закрыть и все
>[оверквотинг удален]
>>
>>Не совсем так, потому что popen() возвращает FILE *, а read() ждёт
>>int в качестве файлового дескриптора. Так что вам, по-видимому, нужно fread()
>>использовать.
>>
>>
>>P.S. Почитайте маны)
>
>Угу уже поитал уже разобрался всем спасиб =) терь тока надо закрыть
>и всехм, открываю получаю данные закрываю
коду получилось в 3 строчки =)
но теперь по завершению в консоли потерян фокус =(((
>[оверквотинг удален]
>>>
>>>
>>>P.S. Почитайте маны)
>>
>>Угу уже поитал уже разобрался всем спасиб =) терь тока надо закрыть
>>и все
>
>хм, открываю получаю данные закрываю
>коду получилось в 3 строчки =)
>но теперь по завершению в консоли потерян фокус =(((делаю так :
int main()
{
char buf[256] = "null";
FILE *oms = popen("patch/OMStip T75 -done wan0","r");if(!oms)
{
printf("Error read file\n");
return EXIT_FAILURE;
}
else
{
printf("Read run\n");
fread(buf,1,256,oms);
printf("%s",buf);
fclose(oms);
}
}но приложение отрабатывет со второго раза о_О, и после исполнения теряется фокус у консоли
в нее ничего нельзя ввести О_О как это побороть?
Где хедеры stdio.h. и stdlib.h ?>int main()
В Си если ф-ция не принимает параметров, лучше указывать void, т.е. в вашем случае правильнее будет
int main(void)
>{
>char buf[256] = "null";
>FILE *oms = popen("patch/OMStip T75 -done wan0","r");
>
>if(!oms)
> {
> printf("Error read file\n");Сообщение об ошибках всё же лучше направлять в stderr. Ну и оно должно быть более читабельным, чем в вашем случае.
> return EXIT_FAILURE;
> }
> else
> {
> printf("Read run\n");
> fread(buf,1,256,oms);У вас размер буфера 256, как вы собрались туда прочитать 256 символов? А как же нулевой символ? Вы так можете получить ошибку off-by-one и выход за границы массива.
> printf("%s",buf);
> fclose(oms);fclose() используется для закрытия файловых дескрипторов, открытых с помощью fopen(). В вашем случае нужно pclose()
> }
>Здесь должен быть оператор return EXIT_SUCCESS;
>}
>
>но приложение отрабатывет со второго раза о_О, и после исполнения теряется фокус
>у консоли
>в нее ничего нельзя ввести О_О как это побороть?У меня ваш пример (после некоторых правок) отрабатывает с первого раза и никакой фокус не теряется.
прошло 4 года, читаю и смеюсь сам над собой =) вот глупый был =)))