Pipe + plik = problem :(:(

0

Witam
Mam pewien problem. Musze zrobie program ktorego zasada dzialania jest nastepujaca. Przesylam do programu nazwe pliku, program tworzy proces potomny ktoremu przekazuje nazwe tego pliku, proces potomny sprawdza czy ten plik istnieje, jezeli nie to zwaraca do procesu macierzystego informacje ze plik nie istnieje a proces macierzy wyswietla to na ekranie, jezeli natomiast plik istnieje proces macierzysty otwiera go czyta z niego i przysyla dane (bufforem) do procesu macierzystego ktory wyswietla zawartosc tego pliku na ekranie. Mi sie udalo zrobic prawie wszystko jedyny problem jaki mam to czytanie z pliku tzn program czyta mi tylko kilka linijek i koniec , nie czyta do konca pliku :(. (nie wiem jak zmusic go do czytania do konca pliku). Prosilbym o pomoc.
Ps zalezy mi zeby to bylo na funkcji open.

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char*argv[])
{
int pid,error,czyt;
int mp[2],pp[2];
pipe(mp);
pipe(pp);
char readbuffer[200]="",readbuffor[200]="",dane[200]="";
if ((pid=fork())==-1)
   {
    printf("Nie mozna stworzyc procesu potomnego");
    exit(0);
   }
if (pid == 0)
   {
    close(mp[1]);
    close(pp[0]);
    read(mp[0],readbuffer,sizeof(readbuffer));
    printf("To jest nazwa przesłanego pliku: %s \n",readbuffer);
    int plik = open(readbuffer,O_RDONLY);
    if (plik == -1)
       {
       write(pp[1],"Plik nie istnieje",20);
       }
    else
       {
       while(czyt != -1)
          {
          czyt = read(plik,dane,sizeof(dane));
          write(pp[1],dane,sizeof(dane));

          }
       }
  }
else
  {
   close(mp[0]);
   close(pp[1]);
   write(mp[1],argv[1],strlen(argv[1]));
   czyt1 = read(pp[0],readbuffor,sizeof(readbuffor));
   printf("%s \n",readbuffor);
  }
}

Pozdrawiam
Pawel

0
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc,char** argv){
  int i;  // jedna zmienna wystarczy i do obslugi procesow i do przesylu danych w koncu co wlasciwie robisz z pidem ? nic poza dwukrotnym porownaniem, dalej w ogole nie jest potrzebny:)
  int mp[2],pp[2];
  
  pipe(mp);
  pipe(pp);
  
  char dane[2048]; // jesli dobrze pomyslisz, to dojdziesz do wniosku, ze nie potrzeba nic ponad jeden bufor. zerowac tez nie musisz, nadrobisz to wyslaniem raz pojedynczego bajta wiecej

  if((i=fork())==-1){
    fprintf(stderr,"Nie mozna stworzyc procesu potomnego\n");
    exit(-1); // Jesli program musi zawiesc, niech zawiedzie z hukiem (stderr / -1) 
  }
  
  if(!i){
    close(mp[1]);
    close(pp[0]);
    read(mp[0],dane,sizeof(dane));
    printf("To jest nazwa przesłanego pliku: %s\n",dane);
    int plik=open(dane,O_RDONLY);
    if(plik==-1){
      char* s="Plik nie istnieje\n";
      i=strlen(s)+1;
      write(pp[1],&i,sizeof(i)); // sorry, taki protokol uzyty :>
      write(pp[1],s,i); // strlen() + 1
    }else{ 
        while((i=read(plik,dane,sizeof(dane)))>0){ // nie !=-1 tylko >0 - 0 znaczy koniec pliku, a ujemne to bledy
	  write(pp[1],&i,sizeof(i)); // wysylamy ilosc bajtow do odebrania
          write(pp[1],dane,i); // ale danych wysylamy dokladnie tyle ile ich odebralismy, ani bajta wiecej
        }
//	i=0;
//	write(pp[1],&i,sizeof(i)); // na tym sie zasadza caly protokol wysylania danych: wyslanie 0 powoduje zakonczenie. Chociaz z drugiej strony, wcale nie musisz tego wysylac , a program tez bedzie dzialal :)
      }
  }else{
    close(mp[0]);
    close(pp[1]);
    write(mp[1],argv[1],strlen(argv[1])+1); // +1, jesli nie zerujesz bufora, to musisz wyslac 0-terminator na koncu nazwy
    while(read(pp[0],&i,sizeof(i))>0 && i){ // najpierw odbierana jest ilosc danych i przypisane i, potem i jest dopiero porownywane do zera, jesli rowne to petla jest przerywana
      int j;
      if((j=read(pp[0],dane,i))<1 || j!=i)break; // lub <=0 tu dopiero czytamy dane i tak samo przerywamy, gdy blad lub koniec pliku, j!=i - sorry tu poszedlem na latwizne, zakladam, ze z pajpa bedzie mozna ZAWSZE odczytac tyle bajtow ile zostalo do niej zapisane, calosc mozna bylo zapisac : if(read(pp[0],dane,i)!=i)
      write(1,dane,i);// po co printf, ktory wymaga formatowania i terminowania ciagu, skoro masz dane w buforze, idealne dla write ?
    }
  }
  
  return 0;
}

pamietaj ze fork tworzy drugi proces, a zmienne z jednego procesu nie maja zadnego wplywu na zmienne z drugiego</cpp>

0

Wielkie dzieki
Choc wyczytalem gdzies tez ze funkcja read zwaraca wartosc 0 gdy bedzie koniec pliku. No ale tak tez mi sie wysypywalo na dluzszych plikach.
Pozdrawiam

0

Witam
Mam kilka pytan zwiazanych z twoja odpowiedzia:) Jezeli moglbys mi wyjasnic troche bardziej nastepujace czesci.

i=strlen(s)+1;
      write(pp[1],&i,sizeof(i)); 
      write(pp[1],s,i); 

Nie rozumiem czemu jest i=strlen +1 rozumiem ze pobierasz dlugosc stringa i zwiekszasz ta wartosc o 1 no ale czemu o jeden ?? I dlaczego pierwsze przesylasz tekst plus zwikszony o jeden a potem zas przesylasz ten tekst?Nie wiem czy dobrze mnie zrozumiales lub czy dobrze sie wyrazilem ale kurde nie moge tego zrozumiec troche. (sorki ale dopiero raczkuje).
write(1,dane,i);
Dla czego tam jest tylko 1 czy moze sie pomyliles czy moze jedynka oznacza zeby to wyswietlic na ekranie ??
TYlko tyle albo az tyle mam pytan.
Z gory wielkie dzieki ;)
Pozdrawiam
i Wesolych Swiat

0

pomylka, moze byc bez tego +1, dziala - wiem, bo sam pozniej tez ten blad zobaczylem i poprawilem, chodzi o to, ze terminatorem jest znak 0, ktory nie jest liczony przez przez length. taki formata danych potrzebny jest dla wiekszosci funkcji operujacych na char*, dal read/write gdzie podaje sie dlugosc bufora danych terminator jest tylko dana, bez specjalnego znaczenia, wiec wlasciwie nawet nie powinno go byc.

write(1,dane,i) nie jest zadna pomylka. numery uchwytow plikow w *niksopodobnych dla wartosci 0-2 sa z gory ustalone i sa odpowiednikami :
0 - stdin (cin uzywajac strumieni)
1 - stdout (cout)
2 - stderr (cerr)

jakbys chcial uzyc printt/fprintf/cout to funkcjonalny odpowiednik wygladalby mniej wiecej tak:

for(int j=0;j<i;j++){ // ponizsze do wyboru
  printf("%c",dane[j]);  
  fprintf(stdout,"%c",dane[j]);
  cout << dane[j];
}

i jeszcze jedna poprawka (ale sam sie domysl o co lotto):

while(read(pp[0],&i,sizeof(i))==sizeof(i) && i){
  int j;
  if((j=read(pp[0],dane,i))<1 || j!=i);
  write(1,dane,i);
}

Jeszcze jedna rzecz: wysylanie i dobieranie nazwy pliku jest calkowicie niezgodne z protokolem, ale są to pierwsze dane i mozna sobie na to odstepstwo pozwolic</cpp>

1 użytkowników online, w tym zalogowanych: 0, gości: 1