2012-04-13 3 views
1

Ich muss ein Programm schreiben, die Pipe senden Dateiname von der Befehlszeile zu untergeordneten Prozess erstellen. Im Kind lesen Sie diese Datei und senden Sie sie mit Hilfe der Pipe zurück. Übergeordneter Prozess sollte die Datei drucken. Wenn ein Fehler im untergeordneten Prozess auftritt, muss der Fehler an den übergeordneten Prozess gesendet werden.Programm, lesen Sie die Datei und senden Sie es an den übergeordneten Prozess mit Rohr

Hier ist mein Code, es drucken einige Junk-Datei Datei (und auch deaktivieren Scrollen im Terminalemulator, wenn ich es ausführen).

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

void main(int argc, char *argv[]) { 
    int pipefd[2]; 
    char buff[100]; 
    int childpid; 
    int size; 
    FILE *file; 

    if (argc != 2) { 
     printf("usage:\n%s <filename>\n", argv[0]); 
     exit(1); 
    } 
    if (pipe(pipefd) < 0) { 
     perror("can't open pipe\n"); 
    } 
    if ((childpid = fork()) == 0) { 
     sleep(1); 
     size = read(pipefd[0], buff, sizeof(buff)); 
     file = fopen(buff, "r"); 
     if (file == NULL) { 
     write(pipefd[1], "Can't open file", 15); 
     exit(1); 
     } 
     while (!feof(file)) { 
     if (fgets(buff, sizeof(buff), file) == NULL) { 
      write(pipefd[1], "Error reading file", 18); 
     } else { 
      write(pipefd[1], buff, sizeof(buff)); 
     } 
     } 
    } else if (childpid > 0) { 
     size = strlen(argv[1]); 
     if (write(pipefd[1], argv[1], size) != size) { 
     perror("Error writing to pipe\n"); 
     } 
     wait(NULL); 
     while ((size = read(pipefd[0], buff, sizeof(buff))) > 0) { 
     write(1, buff, size); 
     } 
    } 
    exit(0); 
} 
+0

Es sollte 'int main (intargc, char * argv [])' sein. –

+0

Können Sie uns sagen, mit welchem ​​Problem Sie konfrontiert sind? –

+0

Wenn die Datei groß genug ist, haben Sie einen Deadlock; Der Elternteil wartet darauf, dass das Kind stirbt, aber das Kind kann aufgehängt werden, während es darauf wartet, dass der Elternteil das Rohr liest. Sie nehmen bidirektionale Rohre an; Diese sind noch nicht Standard (obwohl sie unter Linux verfügbar sind, glaube ich). Ihr Elternprozess sollte das Schreibende seiner Pipe schließen, wenn es fertig ist, darauf zu schreiben; wohl sollte das Kind das Leseende seiner Leitung schließen, wenn es fertig ist, es zu lesen. –

Antwort

2

Ihr Programm funktioniert nach einigen Änderungen wie gewünscht. Lets list, was alle Änderungen benötigt werden und warum -

I) Sowohl im Kind und Eltern, schließen Sie die entsprechenden Rohre, sobald Sie mit ihnen fertig sind. Von man page von read(3),

Wenn einige Verfahren das Rohr zum Schreiben geöffnet hat und O_NONBLOCK ist klar, read() wird der aufrufende Thread blockiert, bis einige Daten geschrieben oder das Rohr durch alle Prozesse geschlossen ist, der hatte das Rohr offen für Schreiben.

Also überall in Ihrem Code so etwas tun, wo die Arbeit Rohre vorbei ist,

size = read(pipefd[0], buff, sizeof(buff)); 
    close(pipefd[0]); 

    write(pipefd[1], buff, strlen(buff)); 
    close(pipefd[1]); 

    if (write(pipefd[1], argv[1], size) != size) { 
    perror("Error writing to pipe\n"); 
    } 
    close(pipefd[1]); 

    while ((size = read(pipefd[0], buff, sizeof(buff))) > 0) 
    { 
    write(1, buff, size); 
    } 
    close(pipefd[0]); 

Sie hatte das Schreibende des Rohrs in das Kind nicht geschlossen und Ihre Eltern versperrte in den read

II) Sie sind mit so etwas wie while(fgets(...)) in einer Schleife Daten aus der Datei zu lesen. Dies wird bombardieren, wenn es neue Zeilen in der Datei und fgets mehrfach zurückgibt, während des Prozesses der buffer jedes Mal überschreiben

Ich benutze immer einfach fgetc und feof Kombination aus einer Datei zu lesen.So ändern Sie Ihre Datei Lesemechanismus zu so etwas wie

unsigned count=0; 
while (!feof(file) && count < sizeof(buff)) 
    buff[count++]=fgetc(file); 
if (feof(file)) 
    buff[--count]=0; 
else 
    buff[sizeof(buff)-1]=0; 

III) Während die Dateidaten von dem Kind zu schreiben, Sie strlen verwenden sollten (wie wir bereits sicher Puffer null beendet wird, siehe oben) und nicht sizeof als der Puffer möglicherweise nicht voll und Sie werden am Ende schreiben Müll. So ändern

write(pipefd[1], buff, sizeof(buff)); 

zu

write(pipefd[1], buff, strlen(buff)); 

IV) ein sicheres exit von dem Kind folgen und Eltern nach ihrer Arbeit erledigt ist. So etwas wie

close(pipefd[1]); 
_exit(EXIT_SUCCESS); // in child 

und

close(pipefd[0]); 
exit(EXIT_SUCCESS); // in parent 

PS: Ich habe die Datei zu lesen Logik geändert, so dass Ihr Compiler-Fehler ist jetzt weg und folgen den gegebenen Ratschläge von n.m.

+0

Und wahrscheinlich zwei Rohre verwenden. Im aktuellen Code lesen und schreiben Eltern und Kind in dieselbe Pipe. – JeremyP

+0

Netter Vorschlag @ JeremyP. Obwohl es in diesem aktuellen Beispiel nicht betroffen ist, ist es eine gute Sache zu tun! –

+0

Vorsicht bei der Verwendung von 'feof()' in der Logik der Hauptschleife. Die einzige Zeit, die Sie normalerweise 'feof()' verwenden, ist der Fehlerbehandlungscode, der zwischen EOF und Dateilese-/Schreibfehler unterscheiden muss, nachdem eine Problemanzeige von einer Funktion wie 'fgets()' erhalten wurde. Alles andere ist etwas zweifelhaft. –

0

Dieser Code nicht kompiliert:

while (fgets(buff, sizeof(buff), file) != NULL) { 
     write(pipefd[1], "Error reading file", 18); 
    } else { 
     write(pipefd[1], buff, sizeof(buff)); 
    } 

Sie keine else Klausel dort haben kann.

+0

Ja ich habe wenn Aussage aber ich entferne es. – jcubic

+0

@jcubic: Es ist schwer genug, den Code anderer Leute zu debuggen; es ist viel schwieriger, etwas zu debuggen, das nicht der Code ist, den sie ausführen. Erfahren Sie, wie Sie Ihren Code auf einen minimalen Testfall reduzieren können, der Ihr Problem veranschaulicht und in die Frage eingefügt werden kann. Es sollte so kurz wie möglich (aber nicht kürzer) sein; ein Ziel sollte 20-50 Zeilen, wobei kürzer ist besser und länger ist OK wenn nötig, aber wenn es länger als etwa 100 Zeilen wird, haben Sie wahrscheinlich nicht genug minimiert. Kann eine Zeile oder Deklaration entfernt werden? –

+0

Entschuldigung, ich habe gerade den Code aktualisiert. Ich dachte, dass dieser Code klein ist, ohne ihn zu verkleinern. Und ich dachte auch, dass diese Art von Code für jemanden, der C und Linux kennt, trivial ist. – jcubic

2

Sie können sizeof(buf) sinnvolle Bytes nicht schreiben, wenn fgets weniger zurückgegeben wird. Der Rest wird mit Müll gefüllt sein.

Darüber hinaus ist die Mischung String-orientierte fgets mit binären read/write ein schlechter Stil. Verwenden Sie read oder fread, um die Datei zu lesen. Sie geben die Anzahl der gelesenen Bytes zurück und verwenden diese Zahl als Argument für write.

Verwandte Themen