LINUX.ORG.RU

Функция popen() - язык СИ

 


2

3

Здравствуйте.

Есть некая программа, неважно что она делает (в крестики-нолики сама с собой играет). В ней есть отдельный поток, задача которого, запускать скрипт «pinre.sh» и считывать результат работы этого скрипта:

#!/bin/sh

BCM0=`cat /home/dima/test.txt`
BCM1=`cat /home/dima/test2.txt`
BCM2=`cat /home/dima/test3.txt`

S2="$BCM0 $BCM1 $BCM2"
echo "$S2"

exit 0

Скрипт опрашивает три файла (test*.txt), собирает результат в строку и делает echo «$S2», тоесть выплёвывает строку «bla1 bla2 bla3».

Вот поток, который запускает скрипт и ловит ответ:

...
void * thr_fnc() 
 { 
   for(;;) 
    { 
      sleep(1);

      FILE * read_pins;
      char in_data[16];

      read_pins = popen("pinre.sh", "r");

      int lastchar = fread(in_data, 1, 15, read_pins);
      in_data[lastchar] = '\0';
      printf("Data:%s", in_data);
      pclose(read_pins);
    } 

   return 0;

 } 
...

Вопрос заключается вот в чём: что из себя в данном случае представляет FILE * read_pins;, это какой-то файл, который создаётся на диске или область в памяти выделяется? Или это ещё что-то?

Перемещено leave из general


popen создаёт трубу «между» FILE* и stdout форкнутой щели, в которой запускается твой скрипт. Физически, да, труба представляет собой буфер FIFO в памяти.

anonymous ()

Есть некая программа, неважно что она делает
FILE * read_pins;

«Я представляю герцога, неважно какого герцога!» ©

anonymous ()

Уровнем ниже создаётся pipe(2), для его поддержания в памяти есть буфер.

Softwayer ★★ ()
Ответ на: комментарий от anonymous

«Я представляю герцога, неважно какого герцога!» ©

Блестяще Фельтон! )))

stD ()
Ответ на: комментарий от anonymous

popen создаёт трубу «между» FILE*

То есть, это не файл, а область памяти, куда заносятся данные?

Форка у меня нет.

Не сердчайте особо, учусь я только. Ман посмотрел, но там внятного объяснения нет, либо я плохо читаю по аглицки.

Вот как перевёл гугл кусок мана:

Функция POPEN () открывает процесс создания канала, ветвление, и вызова оболочки. Так как труба является
       определение однонаправленным, аргумент типа может указать только чтение или запись, но не оба; результирующий
       поток, соответственно, только для чтения или только для записи.

       Аргумент команды является указателем на завершающуюся нулем строку, содержащую командную строку оболочки. Эта команда
       передается / бен / ш, используя флаг -c; интерпретации, если таковые вообще имеются, осуществляется оболочки. Аргумент типа
       является указателем на строку с завершающим нулем, которая должна содержать либо букву 'R' для чтения или письма
       'W' для записи. Так как GLibC 2.9, этот аргумент может дополнительно включать в себя букву «е», что вызывает
       закрыть при выполнении Exec флаг (FD_CLOEXEC), который будет установлен на основной дескриптор файла; см описание
       O_CLOEXEC флаг в открытых (2) по причинам, почему это может быть полезно.

       Возвращаемое значение из POPEN () является нормальным стандартным I / O поток во всех отношениях кроме того, что оно должно быть закрыто
       pclose (), а не fclose (3). Запись в такой поток записывает в стандартный поток ввода команды;
       Стандартный результатов работы команды является такой же, как в процессе, который называется POPEN (), если это не будет изменено
       сама команда. С другой стороны, чтение из "popened" поток считывает стандартный вывод команды, и
       Стандартный командный ввод является такой же, как в процессе, который называется POPEN ().

       Обратите внимание, что выходной POPEN () потоки полностью буферизованный по умолчанию.
stD ()
Ответ на: комментарий от stD

>Физически, да, труба представляет собой буфер FIFO в памяти.

Просто меня смутило это «FILE *», подумалось что создаётся файл.

stD ()
Ответ на: комментарий от stD

Файл в C более широкое понятие, чем наиболее привычный файл с данными на каком-то хранилище. Это и стандартные потоки ввода-вывода и, например, последовательные порты и сетевые соединения(это с некоторой натяжкой, но к данной теме можно, я считаю). То есть это некоторая сущность, из которой можно прочитать данные.

Elyas ★★★★★ ()

Запуск скрипта в «потоке» было легче сделать, чем считывание данных из файлов на сях?

Deleted ()
Ответ на: комментарий от stD

Вообще, FILE — это тип структуры, которая объявлена в <libio.h> под названием _IO_FILE. Эта структура описывает файловый дескриптор, который используется в системных вызовах, таких, как, например, pipe, который вызывается из popen для создания анонимного канала между двумя процессами — твоей программой и скриптом.

Все файловые дескрипторы процесса перечислены в /proc/PID/fd/, где PID — идентификатор процесса. Дескрипторы 0, 1 и 2 — это stdin, stdout и stderr соответственно, они создаются операционной системой автоматически при запуске процесса.

В структуре FILE поле со значением файлового дескриптора называется _fileno. То есть read_pins->_fileno покажет тебе значение твоего нового файлового дескриптора.

Форка у меня нет.

Системный вызов fork тоже вызывается из popen.

Мануалы тебе лучше почитать вот эти: man 7 pipe, man 7 fifo.

anonymous ()
Ответ на: комментарий от Elyas

Это и стандартные потоки ввода-вывода и, например, последовательные порты и сетевые соединения. То есть это некоторая сущность

Это я отчасти понимаю, просто хочется понять, что в данном случае представляет из себя эта сущность, она же имеет какое-то физическое представление в компьютере, ну не в воздухе же данные висят))).

Правильно ли я понимаю, что в данном случае «FILE *» - это какая то выделеная область памяти?

...

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

...

Скажите ещё пожалуйста, можно ли таким же образом передавать данные между форками (родительским и дочерним процессом)?

stD ()
Ответ на: комментарий от stD

передавать данные между форками (родительским и дочерним процессом)?

Да http://tldp.org/LDP/lpg/node11.html

Форка у меня нет.

Есть. The popen() function opens a process by creating a pipe, forking, and invoking the shell. Как иначе ты подпроцесс запустишь?

pawnhearts ★★★★★ ()
Ответ на: комментарий от Deleted

Запуск скрипта в «потоке» было легче сделать, чем считывание данных из файлов на сях?

Изначально у меня была идея, вместо скрипта, сделать некий конфигурационный файл (с названиями файлов), который будет скармливаться программе при старте, а пользователь сможет с лёгкостью вносить изменения в конфиг. Однако придётся много чего менять. Мне трудно объяснить весь алгоритм работы программы, это часть онлайн конструктора, и там много всяких заковык.

stD ()
Ответ на: комментарий от anonymous

Мануалы тебе лучше почитать вот эти: man 7 pipe, man 7 fifo.

Спасибо, прочту. Много информации на меня обрушилось.

stD ()
Ответ на: комментарий от pawnhearts

Есть. The popen() function opens a process by creating a pipe, forking, and invoking the shell. Как иначе ты подпроцесс запустишь?

Извиняюсь, думал что форк это когда:

...
process = fork();

      if(-1 == process) 
       {
         error_log("Not udp_PID");
       }
...
stD ()
Ответ на: комментарий от stD

Скажите ещё пожалуйста, можно ли таким же образом передавать данные между форками (родительским и дочерним процессом)?

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

Elyas ★★★★★ ()
Ответ на: комментарий от Elyas

Если же после форка обмен данными со своим же кодом, то вариантов больше.

Если не затруднит, опишите их вкратце...

stD ()
Ответ на: комментарий от stD

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

Elyas ★★★★★ ()
Ответ на: комментарий от Elyas

Напомню, что при форке потомок имеет прямой доступ ко всем данным родителя

Шутить изволите?

stD ()
Ответ на: комментарий от stD

Данные да, но открытые файловые файловые дескрипторы наследуются. Правда их можно передать и так вообще в другой процесс через unix сокет.

pawnhearts ★★★★★ ()
Ответ на: комментарий от stD

Форка у меня нет.

У тебя там есть форк и не один, сначала popen сделает форк и exac чтобы запустить шел, а потом bash сделает еще раз форк и exac, чтобы запустить твоею программу в данном случае «pinre.sh», даже если бы у тебя это был бы скрипт, а бинарник, popen все равно сначала запустил бы шел.

Переменные ведь тоже изолированы?

Да, гугли copy on write. Но все, что касается дескрипторов у них общее, т.е. например если ты читаешь файл в одном процессе, то в другом позиция тоже сдвинется, т.к. в программе лежит только дескриптор указывающий на объект в ядре, который один на двоих

mythCreator ()
Ответ на: комментарий от mythCreator

Переменные ведь тоже изолированы?

Да,

Спасибо.

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

Не совсем понял, то есть ядро видит один дескриптор (например для файла bla.txt дескриптор будет 3457, его видит ядро). Я в одной программе открываю файл с дескриптором 3457 и в другой программе открываю этот же файл с дескриптором 3457. Так?

Или мне спать уже пора?)

stD ()
Ответ на: комментарий от mythCreator

если ты читаешь файл в одном процессе, то в другом позиция тоже сдвинется

Честно?

Sorcerer ★★★★★ ()
Ответ на: комментарий от stD

Не совсем понял, то есть ядро видит один дескриптор (например для файла bla.txt дескриптор будет 3457, его видит ядро). Я в одной программе открываю файл с дескриптором 3457 и в другой программе открываю этот же файл с дескриптором 3457. Так?

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

mythCreator ()
Ответ на: комментарий от stD

Вот не большой пример, того о чем я говорю

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
    pid_t p;
    char buff[16];
    int fd = open("bla.txt", O_RDONLY);
    p = fork();
    if (p == 0) {
        sleep(2);
        read(fd, buff, 5);
        printf("Child fd = %d, buff = %s\n", fd, buff);
        close(fd);
    } else {
        read(fd, buff, 5);
        printf("Parent fd = %d, buff = %s\n", fd, buff);
        close(fd);
        wait();
    }
}

Напиши в файл bla.txt HelloWorld и посмотри, что будет

mythCreator ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.