ТОП 10:

Переспрямування потоків введення-виведення у POSIX



Реалізація переспрямування потоків введення-виведення у POSIX ґрунтується на тому, що наперед визначені дескриптори не закріплені за конкретними файлами. Перед створенням процесу або під час його виконання можна змінити відповідний елемент таблиці дескрипторів так, щоб він посилався на інший відкритий файл. У результаті всі системні виклики, що використовують як параметр цей файло­вий дескриптор, працюватимуть із цим файлом, а не з керуючим терміналом.

Для переспрямування потоків введення-виведення необхідно, щоб наперед ви­значений файловий дескриптор посилався на той самий файл, що і наявний деск­риптор oldfd,відкритий за допомогою орепО.Щоб змусити наявний дескриптор посилатися на той самий файл, що й інший відкритий дескриптор, можна вико­ристати системний виклик dup2().

intdup2(int fd1. int newfd);

де: fd1— вихідний відкритий дескриптор;

newfd— наявний дескриптор, що посилатиметься на той самий файл, що і fdl.

Ось приклад переспрямування потоку виведення:

int fd1:

write(STD0UT_FILENO. "на консоль\п", 11);

fdl = open(’’output-log.txt".0_CREAT|0_RDWR. 0644);

// переспрямування виведення, аналог myprog > output-1og.txt

dup2(fd1,STDOUTJILENO):

// тут STD0UT_FILEN0 посилається на той самий файл, що й fdlwri te(STD0UT_FIL ENO. "у файл\п", 7); close(fd1):

Зазначимо, що виклик close ()у цьому разі закриє тільки один із двох деск­рипторів, STDOUT_FILEN0 залишиться відкритим, і через нього можна продовжувати роботу із файлом.

Подібний код можна використати і для переспрямування потоків введення-виведення процесу-нащадка (як це робить командний інтерпретатор), тут виклики ореп() і dup2() виконують у нащадку після виклику fork(), але перед викликом ехес().

Переспрямування потоків введення-виведення у Win32

Для реалізації переспрямування потоків введення-виведення в рамках одного про­цесу у Win32 використовують функцію SetStdHandlе()

 

BOOL SetStdHandlе(DWORD std_const.HANDLE fh):

 

Тут std_const набуває тих самих значень, що і для GetStdHandle(), a fh відобра­жає відкритий файл.

 

DWORD bytes_written;

HANDLE fd. stdout:

// одержати стандартний дескриптор

stdout = GetStdHandle(STD_OUTPUT_HANDLE);

// вивести дані у файл стандартного виводу

WriteFile(stdout. "на консоль\n", 11. &bytes_written. 0);

fh ч CreateFile(‘’output-log.txt". GENERIC_WRITE. ...):

// переспрямування виведення, аналог myprog.exe > output-log.txt

SetStdHandle(STD_OUTPUT_HANDLE. fh);

Wn'teFile(stdout. "у файл\п". 7. &bytes_written. 0):

 

Використання каналів

Кілька фільтрів можна об'єднувати для обробки даних за допомогою каналів, при цьому стандартний вивід одного процесу переспрямовують на стандартний ввід іншого:

 

$ grep linux * I sort

 

У цьому разі результати виконання утиліти дгер передаватимуться на стан­дартний ввід утиліті sort. Канали можуть об'єднувати будь-яку кількість процесів.

Ще один спосіб використання каналів зводиться до обміну даними між про­цесом і командним інтерпретатором, під час якого результати виконання процесу будуть підставлені в командний рядок інтерпретатора. Таку технологію назива­ють командною підстановкою (command substitution), для цього командний ря­док виклику застосування, результати виконання якого потрібно використати, беруть у зворотні лапки: ~виконуваний_файл параметри1.

 

$ grep linux 'cat filelist.txt'

 

У даному випадку файл filelist.txt містить список імен файлів, у яких потрібно зробити пошук. Внаслідок виконання утиліти cat список має видаватись на стан­дартний вивід, але замість цього його підставляють у командний рядок виклику утиліти grep.

 

Реалізація каналів у POSIX

Для реалізації описаного обміну даними між процесами використовують техно­логію безіменних каналів (див. розділ 6). Такий канал забезпечує однобічне пере­давання даних від одного процесу до іншого (тобто коли один процес у канал пи­ше, другий може із нього читати і навпаки).

Безіменний канал відкривають за допомогою системного виклику ріре():

 

#include<unistd.h>

int pipe(int fifo[2]):

 

Тут f і f о — масив із двох файлових дескрипторів, що складають канал: один із них використовують для записування, інший — для читання. Один процес може записувати дані у fifo[0], тоді інший зчитуватиме ці дані із fifo[l]; якщо ж пер­ший процес запише у fifo[l], то другий зчитає з fifo[0]. Спроби читання забло-кують, якщо в канал не надійшли дані, спроби записування - якщо не було спро­би читання.

Одним із способів використання безіменних каналів є переспрямування стан­дартного потоку введення або виведення нащадка на один із дескрипторів каналу у тому випадку, коли нащадок запускає зовнішнє застосування [24]. При цьому результати виведення застосування можуть бути зчитані у предку із каналу, а да­ні, які предок записує в канал, стають, у свою чергу, доступні у застосуванні. Роз­глянемо приклад отримання доступу до результатів виконання іншого застосу­вання (він може бути основою реалізації командної підстановки).

 

int pipefd[2], bytes_read, status:

pipe(pipefd);

if ((pid – fork())==-1) exit();

if ((pid==0) { // нащадок

close(pipefd[0]): // закриття дескриптора для читання

// переспрямування виведення на дескриптор для записування

dup2(pipefd[l], STD0UTFILEN0):

// запуск застосування (execveC...)) або виконання коду нащадка } else { // предок

close(pipefd[l]); // закриття дескриптора для записування II ... читання даних у циклі з pipefd[0] close(pipefd[0]); // закриття дескриптора для читання

waitpid(pid, &status. 0):

}

 

Безіменні канали Win32

Для створення безіменного каналу у Win32 використовують функцію CreatePipeC):

 

BOOL CreatePipeCPHANDLE rpipe. PHANDLE wpipe,

LPSECURITY_ATTRIBUTES psa, DWORD size ):

 

де: грі rpiре, wpi ре — покажчики на дескриптори для читання і записування каналу;

size - розмір буфера для каналу (0 - розмір за замовчуванням).

 

Розглянемо, як задати переспрямування потоків введення-виведення проце-сів-нащадків [50].

♦ Під час створення каналу для нього має бути дозволене успадкування деск­рипторів (передаванням у CreatePipeC) структури SECURITY_ATTRIBUTES із полем blnheritHandle, рівним TRUE).

♦ Потрібно задати певні поля структури STARTUPINF0 перед її передачею у функ­цію CreateProcessO. Зокрема, встановлення полів hStdlnput, hStdOutput і hStdEr-ror спричиняє задания стандартних дескрипторів нащадка. Якщо стандартний дескриптор треба переспрямовувати, йому присвоюють один із дескрипторів каналу, якщо ні — дескриптор, отриманий за допомогою GetStdHandleC):

 

// стандартне введення нащадка переспрямовують

si.hStdOutput - wpipe; // wpipe отриманий з CreatePipe()

// стандартне виведення нащадка не переспрямовують si.hStdlnput - GetStdHandlе(STD_INPUT_HANDLE);

 

Крім того, полю dwFlags надається значення STARTF_USESTDHANDLES.

 

♦ Під час виклику CreateProcess() параметру blnheritHandles задається значення TRUE. Після виклику необхідно закрити дескриптор для записування (щоб процес-нащадок завершив своє виведення), зчитати дані з дескриптора для читання, після чого його закрити.

 

HANDLE грі ре. wpipe;

STARTUP INFO Si = {0}; PROCESS_INFORMATION pi;

SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES). NULL. TRUE};

CreatePipe(&rpipe. &wpipe, &sa. 0);

// переспрямування виведення нащадка на дескриптор для записування

si.hStdOutput = wpipe;

si.hStdlnput = GetStdHandle(STD_INPUT_HANDLE);

si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

si.dwFlags - STARTFJJSESTDHANDLES:

CreateProcess(NULL. "cmd /с dir". NULL. NULL. TRUE, 0, NULL.

NULL. &si. &pi); CloseHandle(pi.hThread);

CloseHandle(wpipe); // закриття дескриптора для записування

// ... читання даних у циклі з гріре >

CloseHandle(rpipe); // закриття дескриптора для читання

WaitForSingleObject(pi.hProcess. INFINITE): CloseHandle(pi.hProcess);

 







Последнее изменение этой страницы: 2017-02-06; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.224.127.143 (0.01 с.)