Mihai Sprinceana
Un forum de programare cu de toate. Va astept sa va inscrieti si sa deveniti moderatori. Oricine este binevenit aici sa se inscrie si sa aiba acces la informatie free! Fiecare este liber sa adauge proiecte programe free etc. Ajutati acest forum sa devina o comunitate puternica unde fiecare invata de la fiecare! Tot ce trebuie sa faceti este sa va inregistrati si fiecare contributie se poate dovedi utila in timp! Forumul este free informatia free dk aveti timp liber ajutati si pe ceilalti si invatati si voi in acelasi timp! Haideti sa facem ceva pt.a ne ajuta intre noi! Cititi regulament postare forum inainte de a posta!
Lista Forumurilor Pe Tematici
Mihai Sprinceana | Inregistrare | Login

POZE MIHAI SPRINCEANA

Nu sunteti logat.
Nou pe simpatie:
ubytzika_senzuala pe Simpatie
Femeie
22 ani
Vrancea
cauta Barbat
22 - 45 ani
Mihai Sprinceana / SO Linux&Unix / Comunicare intre procese prin pipes(proiect) Moderat de Cristy89, Houssey, cr3us, fireratbat, profu.info, sade5000
Autor
Mesaj Pagini: 1
Catalin
Moderator

Inregistrat: acum 16 ani
Postari: 19
Comunicare intre procese folosind pipes                                                           





               
Introducere in Linux

Ce este Linux.

Linux este o copie a sistemului de operare UNIX, care poate rula pe un calculator cu procesor Intel 386 sau mai bun.
Linux nu este UNIX, UNIX fiind un software aflat sub copyright (trebuie cumparata o licenta pentru a-l putea utiliza legal).
A fost rescris de la zero pentru a elimina necesitatea platii licentei. Totusi el se bazeaza in intregime pe comenzile si "look and feel"-ul UNIX, deci cine stie Linux stie si UNIX si invers.
Linux este un sistem multiuser si multitasking, adica mai multi utilizatori pot rula mai multe programe in acelasi timp.
Are suport pentru retea (TCP/IP), Internet, ba chiar este unul dintre cele mai folosite sisteme de operare pentru servere internet si intranet. 
Linux este sub licenta GPL ceea ce inseamna urmatoarele:
- este disponibil in cod sursa gratuit.
- oricine vrea sa aduca modificari, sau sa foloseasca anumite parti este liber sa o faca, dar cu conditia ca produsul nou obtinut sa fie sub aceeasi licenta (adica sa fie gratuit si cu sursele la vedere).

Scurt istoric. Cum a aparut Linux

In 1991 Linus Torvalds (pe atunci student) a scris prima versiune de Linux. Apoi a facut publice sursele pe internet, si o multime de oameni au inceput sa-i raspunda, sa-i aduca imbunatatiri, noi sugestii, etc.
Intre timp acest sistem de operare a devenit complex, au aparut (si mai apar) noi facilitati, iar performanta este remarcabila.
In prezent sunt estimati peste 8 milioane de utilizatori Linux, iar nucleul Linuxului are peste 200 de autori. Pe langa acesti 200 de autori ar trebui adaugate cele cateva mii de persoane care testeaza si gasesc buguri.

Ce tip de calculator poate rula Linux ?

Pentru a rula Linux aveti nevoie de minim un calculator i386 cu 4 Mb RAM si 50 Mb spatiu liber pe harddisk.
Daca doriti sa folositi si sistemul X-Windows, minimul de memorie RAM este de 8 MB.
Este posibil ca unele programe complexe sa necesite foarta multa memorie. Linux are posibilitatea de a simula memoria RAM folosind un fisier de swap pe harddisk, dar este mult mai lent.
In plus excesul de memorie este folosit pentru accelerarea operatiilor pe disk, deci cu cat mai multa memorie RAM, cu atat Linux-ul dvs. are performante mai bune.





Programe disponibile sub Linux:

Majoritatea distributiilor Linux includ compilatoare pentru diverse limbaje de programare, utilitare pentru retea (email, telnet, ftp, www), creare si manipulare documente, tiparire, arhivare, si multe altele.
Pe langa acestea exista disponibile pe Internet o mare varietate de programe, unele gratuite, altele nu, iar mai nou marile case de software au inceput sa porteze softurile lor pe Linux.

Iata cateva exemple:
•    Staroffice (foarte asemanator cu MS-Office, gratuit pentru folosire non-comerciala)
•    WordPerfect (Cunoscutul procesor de text, disponibil si sub Linux)
•    Netscape Navigator, Opera (browsere Web)
•    Oracle (baze de date)
•    Mathematica (calcul simbolic si nu numai)
Adrese utile:

Adresele web de mai jos constituie un foarte bun punct de start. Pentru a le accesa aveti nevoie de un calculator conectat la Internet si echipat cu un browser www (Netscape, Opera).

Informatii despre Linux si programe disponibile in Linux:





Informatii despre distributii Linux:



•    htttp://www.caledra.org


Cerintele Hardware

    De la inceput, Linuxul a avut nevoie de resurse hardware minime pentru a rula. Acest lucru nu s-a schimbat in timp. Linuxul poate functiona pe sisteme hard foarte limitate insa a fi capabil sa rulezi Linuxul nu este totuna cu a crea un sistem server.
    Evident, cu cat este mai bun hardware-ul cu atat performanta obtinuta la rularea sistemului de operare va fi mai mare. Cu toate acestea feriti-va de ultimele descoperiri in domeniu pentru ca de multe ori acestea nu sunt suportate de Linux. De exemplu, daca o placa video cu ultimele facilitati a aparut pe piata ieri nu va asteptati ca maine Linux-ul sa o si recunoasca. Uneori producatorii hardware ingreuneaza accesul dezvoltatorilor Linux la informatiile specifice necesare pentru a scrie modulele driver si astfel devine dificil ca acestia sa implementeze rapid ultimele produse hardware.


Pregatirea instalarii

    Red Hat Linux, distributia Linux la care va face referire materialul in continuare, se poate instala prin intermediul serviciilor FTP, NFS sau SMB (Samba) atunci cand CD-ROM-ul Red Hat se afla pe un alt computer. Aceste metode sunt foarte sensibile si de putie ori functioneaza fara erori. Pentru a economisi timp si efort este recomandabil sa realizati instalarea folosind CD-ROM-ul de pe calculatorul pe care instalati Linux-ul.
    Deoarece aceasta este medoda recomandata, vom considera in continuare ca faceti instalarea de pe CD-ul propriu.
    Pasul urmator in pregatirea instalarii il constituie determinarea necesitatii unei dischete boot. Daca aveti un sistem de calcul care suporta bootarea de pe CD-ROM atunci nu aveti nevoie de o astfel de discheta. Insa daca CD-ul dumneavoastra cu distributia Red Hat nu este bootabil sau sistemul nu suporta bootarea (incarcarea) de pe CD-ROM aveti nevoie de o discheta de boot.
   

Crearea dischetelor de bootare
   
Crearea unei dishete de boot sub sistemul de operare Windows se face in felul urmator:

1.    Sa presupunem ca CD-ROM-ul este drive-ul D: si ca aveti deja CD-ul in unitate. Rulati urmatoarea comanda de la un prompt MS-DOS:

d:/dosutils/rawrite

2.    Utilitarul rawrite va afisa urmatoarele:

Enter disk image source file name:

Please insert a formated diskette into drive A: and press the enter key

3.    Introduceti ca sursa \images\boot.img. Rawrite va afisa urmatorul prompt:

Enter target diskette drive:

4.    Introduceti litera corespunzatoare (A: sau a: )
5.    Acum ar trebui sa introduceti o discheta goala, formatata si sa apasati tasta Enter ca sa continue scrierea dischetei.
6.    Utilitatea rawrite va scrie fisierul boot.img pe discheta.

Crearea unei dishete de boot sub sistemul de operare Linux se face in felul urmator:

1.    Montati CD-ROM-ul Red Hat ca de obicei (de ex. mount /dev/cdrom /mnt/cdrom). Considerand ca ati efectuat montarea in directorul /mnt/cdrom schimbati directorul curent in /mnt/cdrom/images, acolo unde este tinuta imaginea de bootare.
2.    Considerand ca discul floppy este /dev/fd0 (standard) si ca utilizati o discheta de 1,44 MB, rulati urmatoarea comanda:

dd if=boot.img of=/dev/fd0 bs=1440K

    In felul acesta ar trebui sa va creati discheta de boot. Va puteti crea, de asemenea, o discheta suplimentara doar inlocuind ca fisier intrare (input file) boot.img cu supp.img (if=supp.img).
    Odata ce aveti discheta puteti instala Red Hat Linux de pe CD.




Introducere in Unix
Unix este denumirea generica a unei largi familii de sisteme de operare orientate pe comenzi, multi-user si multi-tasking, dezvoltat pentru prima data in anii '70 la compania AT&T si Universitatea Berkeley. In timp, a devenit un sistem de operare foarte raspindit in intreaga lume, atit in mediile de cercetare si de invatamint (universitare), cit si in mediile industriale/comerciale.
Ce inseamna sistem de operare orientat pe comenzi ?
Sistemul poseda un interpretor de comenzi, ce are aceeasi sarcina ca si command.com-ul din MS-DOS, si anume aceea de a prelua comenzile introduse de utilizator, de a le executa si de a afisa rezultatele executiei acestora.
Ce inseamna sistem de operare multi-user ?
Un astfel de sistem este caracterizat prin faptul ca exista conturi utilizator, ce au anumite drepturi si restrictii de acces la fisiere si la celelalte resurse ale sistemului. De aceea, se utilizeaza mecanisme de protectie, cum ar fi parolele pentru conturile utilizator. De asemenea, un astfel de sistem permite conectarea la sistem si lucrul simultan a mai multor utilizatori.
Ce inseamna sistem de operare multi-tasking ?
Intr-un astfel de sistem se executa simultan mai multe programe (programele aflate in executie sunt numite procese).
Observatie: de fapt, cind Unix-ul este utilizat pe calculatoare uni-procesor, in asemenea situatie executia simultana (concurenta) a proceselor nu este true-parallelism, ci se face tot secvential, prin interleaving (intretesere), si anume prin mecanismul de time-sharing: timpul procesor este impartit in cuante de timp, si fiecare proces existent in sistem primeste periodic cite o cuanta de timp in care i se aloca procesorul si deci este executat efectiv, apoi este intrerupt si procesorul este alocat altui proces care se va executa pentru o cuanta de timp din punctul in care ramasese, apoi va fi intrerupt si un alt proces va primi controlul procesorului s.a.m.d.
Mecanismul acesta de stabilire a modului de alocare a procesorului proceselor din sistem, se bazeaza pe una din strategiile: round-robin, prioritati statice, prioritati dinamice, s.a. In cazul Unix-ului, se utilizeaza strategia cu prioritati dinamice.
Unix-ul este un sistem de operare multi-user si multi-tasking ce ofera utilizatorilor numeroase utilitare interactive. Pe linga rolul de sistem de exploatare, scopul lui principal este de a asigura diferitelor taskuri (procese) si diferitilor utilizatori o repartizare echitabila a resurselor calculatorului (memorie, procesor/procesoare, spatiu disk, imprimanta, programe utilitare, accesul la retea, etc.) si aceasta fara a necesita interventia utilizatorilor.
Unix-ul este inainte de toate un mediu de dezvoltare si utilizatorii au la dispozitie un numar foarte mare de utilitare pentru munca lor: editoare de text, limbaje de comanda (shell-uri), compilatoare, depanatoare (debugger-e), sisteme de prelucrare a textelor, programe pentru posta electronica si alte protocoale de acces Internet, si multe alte tipuri de utilitare.
Pe scurt, un sistem Unix este compus din:
•    un nucleu (kernel), ce are rolul de a gestiona memoria si operatiile I/O de nivel scazut, precum si planificarea si controlul executiei diferitelor task-uri (procese).
Este intrucitva similar BIOS-ului din DOS.
•    un ansamblu de utilitare de baza, cum ar fi:
o    diferite shell-uri(= interpretoare de limbaje de comanda);
o    comenzi de manipulare a fisierelor;
o    comenzi de gestiune a activitatii sistemului (a proceselor);
o    comenzi de comunicatie intre utilizatori sau intre sisteme diferite;
o    editoare de text;
o    compilatoare de limbaje (C, Fortran, s.a.) si un link-editor;
o    utilitare generale de dezvoltare de programe: debugger-e, arhivatoare, gestionare de surse, generatoare de analizoare lexicale si sintactice, etc.
o    diferite utilitare filtru (= programe ce primesc un fisier la intrare, opereaza o anumita transformare asupra lui si scriu rezultatul ei intr-un fisier de iesire), spre exemplu: filtru sursa Pascal->sursa C, filtru fisier text DOS->fisier text Unix si invers, etc.
Nota: fisierele text sub DOS se deosebesc de fisierele text sub Unix prin faptul ca sfirsitul de linie se reprezinta sub DOS prin 2 caractere CR+LF (cod ASCII: 13+10), pe cind sub Unix se reprezinta doar prin caracterul LF.



Canale interne. Primitiva pipe
Deci un canal intern este un canal aflat in memorie, prin care pot comunica doua sau mai multe procese. Crearea unui canal intern se face cu ajutorul functiei pipe.
Interfata functiei pipe este urmatoarea:
int pipe(int *p)
unde:
•  p = parametrul efectiv de apel trebuie sa fie un tablou int[2] ce va fi actualizat de functie astfel:
•    p[0] va fi descriptorul de fisier deschis pentru capatul Read al canalului;
•    p[1] va fi descriptorul de fisier deschis pentru capatul Write al canalului;
iar valoarea int returnata este 0, in caz de succes (daca s-a putut crea pipe-ul), sau -1, in caz de eroare.
Efect: in urma executiei functiei pipe se creeaza un canal intern si este deschis la ambele capete - in scriere la caparul referit prin p[0], respectiv in citire la caparul referit prin p[1].
Dupa crearea unui canal intern, scrierea in acest canal si citirea din el se efectueaza la fel ca pentru fisierele obisnuite. Si anume, citirea din canal se va face prin intermediul descriptorului p[0] folosind functiile de citire uzuale (read, respectiv fread sau fscanf daca se foloseste un descriptor de tip FILE*), iar scrierea in canal se va face prin intermediul descriptorului p[1] folosind functiile de scriere uzuale (write, respectiv fwrite sau fprintf daca se foloseste un descriptor de tip FILE*).
Observatie importanta:
Pentru ca doua sau mai multe procese sa poata folosi un pipe pentru a comunica, ele trebuie sa aiba la dispozitie cei doi descriptori p[0] si p[1] obtinuti prin crearea pipe-ului, deci procesul care a creat pipe-ul va trebui sa le "transmita" cumva celuilalt proces.
De exemplu, in cazul cind se doreste sa se utilizeze un canal intern pentru comunicarea intre doua procese de tipul parinte-fiu, atunci este suficient sa se apeleze primitiva pipe de creare a canalului inaintea apelului primitivei fork de creare a procesului fiu. In acest fel in procesul fiu avem la dispozitie cei doi descriptori necesari pentru comunicare prin intermediul acelui canal intern.
La fel se procedeaza si in cazul apelului primitivelor exec (deoarece descriptorii de fisiere deschise se mostenesc prin exec).
De asemenea, trebuie retinut faptul ca daca un proces isi inchide vreunul din capetele unui canal intern, atunci nu mai are nici o posibilitate de a redeschide ulterior acel capat al canalului.

Caracteristici si restrictii ale canalelor interne:
1.    Canalul intern este un canal unidirectional, adica pe la capatul p[1] se scrie, iar pe la capatul p[0] se citeste.
Insa toate procesele pot scrie la capatul p[1], si/sau sa citeasca la capatul p[0].
2.    Unitatea de informatie pentru canalul intern este octetul. Adica, cantitatea minima de informatie ce poate fi scrisa in canal, respectiv citita din canal, este de 1 octet.
3.    Canalul intern functioneaza ca o coada, adica o lista FIFO (= First-In,First-Out), deci citirea din pipe se face cu distrugerea (consumul) din canal a informatiei citite.
Asadar, citirea dintr-un pipe difera de citirea din fisiere obisnuite, pentru care citirea se face fara consumul informatiei din fisier.
4.    Dimensiunea (i.e. capacitatea) canalului intern este limitata la o anumita dimensiune maxima (4ko, 16ko, etc.), ce difera de la un sistem Unix la altul.
5.    Citirea dintr-un canal intern (cu primitiva read):
o    Apelul read va citi din canal si va returna imediat, fara sa se blocheze, numai daca mai este suficienta informatie in canal, iar in acest caz valoarea returnata reprezinta numarul de octeti cititi din canal.
o    Altfel, daca canalul este gol, sau nu contine suficienta informatie, apelul de citire read va ramine blocat pina cind va avea suficienta informatie in canal pentru a putea citi cantitatea de informatie specificata, ceea ce se va intimpla in momentul cind alt proces va scrie in canal.
o    Alt caz de exceptie la citire, pe linga cazul golirii canalului:
daca un proces incearca sa citeasca din canal si nici un proces nu mai este capabil sa scrie in canal vreodata (deoarece toate procesele si-au inchis deja capatul de scriere), atunci apelul read returneaza imediat valoarea 0 corespunzatoare faptului ca a citit EOF din canal.
In concluzie, pentru a se putea citi EOF din pipe, trebuie ca mai intii toate procesele sa inchida canalul in scriere (adica sa inchida descriptorul p[1]).
Observatie: La fel se comporta si celelalte functii de citire (fread, fscanf, etc.) la citirea din canale interne.
6.    Scrierea intr-un canal intern (cu primitiva write):
o    Apelul write va scrie in canal si va returna imediat, fara sa se blocheze, numai daca mai este suficient spatiu liber in canal, iar in acest caz valoarea returnata reprezinta numarul de octeti efectiv scrisi in canal (care poate sa nu coincida intotdeauna cu numarul de octeti ce se doreau a se scrie, caci pot apare erori I/O).
o    Altfel, daca canalul este plin, sau nu contine suficient spatiu liber, apelul de scriere write va ramine blocat pina cind va avea suficient spatiu liber in canal pentru a putea scrie informatia specificata ca argument, ceea ce se va intimpla in momentul cind alt proces va citi din canal.
o    Alt caz de exceptie la scriere, pe linga cazul umplerii canalului:
daca un proces incearca sa scrie in canal si nici un proces nu mai este capabil sa citeasca din canal vreodata (deoarece toate procesele si-au inchis deja capatul de citire), atunci sistemul va trimite acelui proces semnalul SIGPIPE, ce cauzeaza intreruperea sa si afisarea pe ecran a mesajului "Broken pipe".
Observatie:
Cele afirmate mai sus, despre blocarea apelurilor de citire sau de scriere in cazul canalului gol, respectiv plin, corespund comportamentului implicit, blocant, al canalelor interne.
Insa, exista posibilitatea modificarii acestui comportament implicit, intr-un comportament neblocant, situatie in care apelurile de citire sau de scriere nu mai ramin blocate in cazul canalului gol, respectiv plin, ci returneaza imediat valoarea -1, si seteaza corespunzator variabila errno.
Modificarea comportamentului implicit in comportament neblocant se realizeaza prin setarea atributului O_NONBLOCK pentru descriptorul corespunzator acelui capat al canalului intern pentru care se doreste modificarea comportamentului, prin intermediul functiei fcntl. Spre exemplu, apelul:
    fcntl(p[1],F_SETFL,O_NONBLOCK);
va seta atributul O_NONBLOCK pentru capatul de scriere al canalului intern referit de variabila p.
Atentie: functiile de nivel inalt (fread/fwrite, fscanf/fprintf, etc.) lucreaza buffer-izat. Ca atare, la scrierea intr-un canal folosind functiile fwrite, fprintf, etc., informatia nu ajunge imediat in canal in urma apelului, ci doar in buffer-ul asociat acelui descriptor, iar golirea buffer-ului in canal se va intimpla abia in momentul umplerii buffer-ului, sau la intilnirea caracterului '\n' in specificatorul de format al functiei de scriere, sau la apelul functiei fflush pentru acel descriptor.
Prin urmare, daca se doreste garantarea faptului ca informatia ajunge in canal imediat in urma apelulului de scriere cu functii de nivel inalt, trebuie sa se apeleze, imediat dupa apelul de scriere, si functia fflush pentru descriptorul asociat capatului de scriere al acelui canal.
Programul - Procesul tata citeste un sir de caractere de la tastatura, sir terminat cu combinatia CTRL+D (i.e., caracterul EOF in Unix), si le transmite procesului fiu, prin intermediul canalului, doar pe acelea care sunt litere mici. Iar procesul fiu citeste din canal caracterele trasmise de procesul parinte si le afiseaza pe ecran.







Codul sursa-
/*
Exemplu de utilizare a unui pipe intern pentru comunicatia intre 2 procese,
folosind functii I/O de nivel scazut.
*/
#include<stdio.h>
#include<errno.h>

extern int errno;

#define NMAX 1000

void main()
{
  int pid, p[2];
  char ch;

  /* creare pipe intern */
  if(pipe(p) == -1)
  {
    fprintf(stderr,"Error: can't open a channel, errno=%d\n",errno);
    exit(1);
  }

  /* creare proces fiu */
  if( (pid=fork()) == -1)
  {
    fprintf(stderr,"Error: can't create a child!\n" );
    exit(2);
  }
    if(pid)
  { /* in tata */
     /* tatal isi inchide capatul Read */
    close(p[0]);

    /* citeste caractere de la tastatura,
       pentru terminare: CTRL+D (i.e. EOF in Unix),
       si le transmite doar pe acelea care sunt litere mici */
    while( (ch=getchar()) != EOF)
      if((ch>='a') && (ch<='z'))
        write(p[1],&ch,1);

    /* tatal isi inchide capatul Write,
       pentru ca fiul sa poata citi EOF din pipe */
    close(p[1]);

   
/* asteapta terminarea fiului */
    wait(0);
  }
  else
  { /* in fiu */
    char buffer[NMAX];
    int nIndex = 0;

    /* fiul isi inchide capatul Write */
    close(p[1]);

    /* fiul citeste caracterele din pipe si salveaza in buffer, pina
       depisteaza EOF, apoi afiseaza continutul bufferului. */
   
    while( read(p[0],&ch,1) != 0)
      if(nIndex < NMAX)
        buffer[nIndex++] = ch;

    buffer[ (nIndex==NMAX) ? NMAX-1 : nIndex ] = '\0';
    printf("Fiu: am citit buffer=%s\n",buffer);

    /* fiul isi inchide capatul Read */
    close(p[0]);
    /* Obs: nu mai era nevoie de acest close explicit, deoarece
       oricum toti descriptorii sunt inchisi la terminarea programului. */
  }
}


Prezentarea powerpoint a proiectului o puteti lua de la link-ul urmator:


pus acum 16 ani
   
mihaispr
Administrator

Inregistrat: acum 16 ani
Postari: 2142
Un alt proiect interesant de la Universitatea din Iasi ce foloseste comunicare intre procese folosind pipes am gasit aici:

IPC:Pipe-uri
Un pipe este un dispozitiv care permite comunicarea unidirecţională între firele
de execuţie ale unui proces, sau între procese părinte şi fiu. Pipe-urile sunt dispozitive
seriale: informaţia este citită din pipe în aceeaşi ordine în care a fost scrisă în pipe.
Pentru a crea un pipe, se apelează int pipe(int pfd[2]); includeţi unistd.h. Se
furnizează primitivei pipe() un tablou de doi întregi, în care aceasta va scrie
descriptorul pentru citire din pipe (pfd[0]) şi descriptorul pentru scriere în pipe
(pfd[1]). Spre deosebire de fişiere, citirea din pipe consumă informaţia citită.
Capacitatea unui pipe este limitată de sistem: încercarea de a scrie într-un pipe "plin"
şi încercarea de a citi dintr-un pipe "gol" vor bloca.
/*determinarea capacitatii unui pipe*/
int pfd[2];
int total=0;
void terminare(void){
printf("Capacitatea unui pipe este de %d octeti!\n", total);
raise(SIGTERM);
}
void main(void){
char c='*';
/*creare pipe*/
pipe(pfd);
/*se executa terminare() la receptionarea SIGALRM*/
signal(SIGALRM, terminare);
/*SIGALRM va fi receptionat peste o secunda*/
alarm(1);
/*se scriu date in pipe, fara a fi consumate*/
while(1){
write(pfd[1], &c, 1);
++total;
}
}
Atunci când un proces creează un proces fiu cu fork(), descriptorii de fişiere
sunt moşteniţi de procesul fiu; în acest fel, cele două procese pot comunica. Evident,
apelul pipe() trebuie să preceadă apelul fork()! Încercarea de a citi dintr-un pipe
închis pentru scriere conduce la recepţionarea EOF; încercarea de a scrie într-un pipe
închis pentru citire conduce la recepţionarea semnalului SIGPIPE.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void producator(const char* mesaj, int contor, FILE* stream){
for(; contor>0; --contor){
fprintf(stream, "%s\n", mesaj);
fflush(stream);
sleep(1);
}
}
void consumator(FILE* stream){
char buffer[1024];
while(!feof(stream) && !ferror(stream) && fgets(buffer, sizeof(buffer), stream)!=NULL)
fputs(buffer, stdout);
}
int main(void){
int pfd[2];
pid_t p;
/*creare pipe*/
pipe(pfd);
/*creare proces fiu*/
p=fork();
if (p){
/*procesul parinte scrie in pipe*/
FILE* stream;
close(pfd[0]);
stream=fdopen(pfd[1], "w" );
producator("Pipe-uri si procese!", 10, stream);
/*fiul trebuie sa poata citi EOF din pipe*/
close(pfd[1]);
waitpid(p, NULL, 0);
}
else{
/*procesul fiu citeste din pipe*/
FILE* stream;
close(pfd[1]);
stream=fdopen(pfd[0], "r" );
consumator(stream);
close(pfd[0]);
}
}
Adeseori este de dorit crearea unui proces fiu care să aibă setat un capăt al
pipe-ului drept intrare sau ieşire standard. Se pot utiliza primitivele int dup(int oldfd)
şi int dup2(int oldfd, int newfd). Primitivele dup() returnează un nou descriptor de
fişier (cel mai mic descriptor disponibil), care partajează cu vechiul descriptor
pointerul de poziţie în fişier. dup2() specifică explicit noul descriptor; dacă acesta
este deja deschis (folosit), îl închide şi îl redeschide corespunzător.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void main(void){
int pfd[2];
pid_t p;
pipe(pfd);
p=fork();
if (p){
/*procesul parinte scrie in pipe si asteapta terminarea fiului*/
FILE* stream;
close(pfd[0]);
stream=fdopen(pfd[1], "w" );
fprintf(stream, "utilizarea functiile I/O din libraria standard\n" );
fprintf(stream, "sirurile de caractere vor fi sortate\n" );
fprintf(stream, "acesta este un test\n" );
fprintf(stream, "procesul fiu este reacoperit\n" );
fprintf(stream, "dup2() redirecteaza intrarea standard in procesul fiu\n" );
fflush(stream);
/*fiul trebuie sa poata citi EOF!*/
close(pfd[1]);
waitpid(p, NULL, 0);
}
else{
/*procesul fiu citeste din pipe si este reacoperit cu sort*/
close(pfd[1]);
dup2(pfd[0], STDIN_FILNO);
execlp("sort", "sort", 0);
}
}
Exemplul anterior poate fi rescris astfel:
#include <stdio.h>
#include <unistd.h>
void main(void){
FILE* stream = popen("sort", "w" );
fprintf(stream, "utilizarea functiile I/O din libraria standard\n" );
fprintf(stream, "sirurile de caractere vor fi sortate\n" );
fprintf(stream, "acesta este un test\n" );
fprintf(stream, "procesul fiu este reacoperit\n" );
fprintf(stream, "dup2() redirecteaza intrarea standard in procesul fiu\n" );
pclose(stream);
}
popen() creează un proces fiu care este reacoperit automat cu sort, înlocuind
astfel apelurile către fork(), dup2() si execlp(). Argumentul "w" indică faptul că
procesul părinte va folosi pipe-ul pentru scriere (implicit, procesul fiu va folosi pipeul
pentru citire). Valoarea returnată de popen() reprezintă capătul pentru scrierea în
pipe; capătul pentru citirea din pipe va fi intrare standard pentru procesul fiu. pclose()
închide capătul pentru scriere, aşteaptă terminarea procesului fiu si returnează
valoarea cu care s-a terminat fiul!
Un pipe extern (FIFO) este un pipe care ocupă o intrare în sistemul de fişiere;
capacitatea sa este deci limitată doar de spaţiul liber disponibil pe disc. Orice proces
poate deschide în scriere/citire un fişier FIFO; astfel, pot comunica prin fişiere FIFO
procese neînrudite! Crearea unui FIFO presupune şi stabilirea proprietarului şi a
drepturilor de acces. Se utilizează primitiva int mkfifo(const char* name, mode_t
mod); includeţi sys/types.h şi stat.h.
pid_t p;
int ffd;
char mesaj[5];
...
mkfifo(argv[1], S_IFIFO|0644);
p=fork();
switch(p){
case -1: fprintf(stderr, "Eroare la fork()\n" ); exit(1);
case 0: ffd=open(argv[1], O_RDONLY);
read(ffd, mesaj,5);
return 0;
default: ffd=open(argv[1], O_WRONLY);
write(ffd, "Salut!",6);
wait(NULL);
return 0;
}
Un FIFO poate fi deschis, simultan, de mai multe procese în scriere sau în
citire. Un proces poate scrie atomic (neîntrerupt) într-un FIFO un bloc de până la
PIPE_BUF octeţi (în Linux, 4K-octeţi). Astfel, dacă există mai multe procese care
scriu simultan într-un FIFO, mesajele scrise pot fi întreţesute la nivel de bloc!
Analog pentru citirile simultane.

Sursa:


pus acum 15 ani
   
Pagini: 1  

Mergi la