2011-10-28 22 views
6

Tôi đang cố gắng thực hiện một chương trình đơn giản -> thực hiện một chương trình khác -> nói "hello" với tiến trình con đó -> đọc lại nội dung -> in nội dung nhận được.C: dup2, pipe and fork không hoạt động như mong đợi

Chương trình được sử dụng khi trẻ chỉ đợi bất kỳ dòng đầu vào nào và in nội dung nào đó thành giá trị chuẩn như "hello there!"

này được chương trình của tôi "host" (có nghĩa là không làm việc):

#include <sys/types.h> 
#include <unistd.h> 
#include <stdio.h> 

#define IN 0 
#define OUT 1 
#define CHILD 0 

main() 
{ 
    pid_t pid; 
    int pipefd[2]; 
    FILE* output; 
    char buf[256]; 

    pipe(pipefd); 

    pid = fork();  
    if (pid == CHILD) 
    { 
    printf("child\n"); 
    dup2(pipefd[IN], IN); 
    dup2(pipefd[OUT], OUT); 
    execl("./test", "test", (char*) NULL); 
    } 
    else 
    { 
    sleep(1); 
    printf("parent\n"); 
    write(pipefd[IN], "hello!", 10); // write message to the process  
    read(pipefd[OUT], buf, sizeof(buf)); 
    printf("received: %s\n", buf); 
    } 
} 

tôi có được điều này:

child 
[.. waits 1 second ..] 
parent 
received: 

tôi thiếu gì? Cảm ơn!

EDIT (test.c):

Bằng cách yêu cầu, đây là chương trình con:

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

int getln(char line[]) 
{ 
    int nch = 0; 
    int c; 

    while((c = getchar()) != EOF) 
    { 
     if(c == '\n') break; 
    line[nch] = c; 
    nch++; 
    } 

if(c == EOF && nch == 0) return EOF; 
return nch; 
} 

main() 
{ 
    char line[20]; 

    getln(line); 
    printf("hello there!", line); 
    fflush(stdout); 
    return 0; 
} 

Trả lời

3

Bạn luôn giả sử đọc từ bộ mô tả tập tin 0 và ghi vào bộ mô tả tập tin 1 với đường ống ... bạn có mối quan hệ này đảo ngược trong quá trình cha mẹ. Đối với những gì bạn muốn làm, bạn có thể cần hai đường truyền thông hai chiều giữa cha mẹ và con để tránh các tình huống mà phụ huynh kết thúc đọc nội dung mà nó viết cho đường ống kể từ khi lập lịch trình là không xác định (nghĩa là, đứa trẻ không được bảo đảm đọc những gì phụ huynh viết cho đường ống nếu phụ huynh cũng đọc từ cùng một đường ống vì cha mẹ chỉ có thể viết và sau đó đọc mà không xen kẽ quá trình con để đọc phụ huynh đã viết).

Thay đổi mã của bạn như sau:

main() 
{ 
    pid_t pid; 
    int pipe_to_child[2]; 
    int pipe_from_child[2]; 
    FILE* output; 
    char buf[256]; 

    pipe(pipe_to_child); 
    pipe(pipe_from_child); 

    pid = fork();  
    if (pid == CHILD) 
    { 
    printf("child\n"); 

    //child process not using these ends of the pipe, so close them 
    close(pipe_to_child[1]); 
    close(pipe_from_child[0]); 

    dup2(pipe_to_child[0], fileno(stdin)); 
    dup2(pipe_from_child[1], fileno(stdout)); 

    execl("./test", "test", (char*) NULL); 
    } 
    else 
    { 
    sleep(1); 
    printf("parent\n"); 
    write(pipe_to_child[1], "hello!\n", 10); // write message to the process  
    read(pipe_from_child[0], buf, sizeof(buf)); 
    printf("received: %s\n", buf); 
    } 
} 
1

Bạn có lẽ nên sử dụng wait hoặc waitpid.

1

Dường như bạn đã mô tả đường ống của bạn bị lẫn lộn. Sau khi gọi số pipe(), pipefd[0] là số đọc đầu cuối của đường ống và pipefd[1]ghi kết thúc của đường ống. Bạn đang viết cho đầu đọc và đọc từ đầu ghi.

Ngoài ra, bạn đang cố gắng sử dụng một ống cho cả stdin và stdout của quá trình con. Tôi không nghĩ rằng đây thực sự là những gì bạn muốn làm (bạn sẽ cần hai ống).

2

Bạn cần hai đường ống cho điều này: một cho stdin của quy trình con và một cho giá trị chuẩn của nó. Bạn không thể tái sử dụng hai đầu của một ống như hai đường ống.

Ngoài ra, dòng này của chương trình cha mẹ

write(pipefd[IN], "hello!", 10); // write message to the process  

không viết một dòng mới, vì vậy getln ở trẻ em sẽ không bao giờ quay trở lại. (Hơn nữa, "hello!" Chỉ có sáu ký tự, nhưng bạn đang viết mười.)

1

Hình như bạn có IN/OUT ngược cho các đường ống - pipefd[0] là kết thúc đọc của ống, vì vậy văn bản cho nó (như phụ huynh không) là vô nghĩa và sẽ thất bại. Tương tự như vậy pipefd[1] là đầu ghi để đọc từ nó (như cha mẹ làm) cũng sẽ thất bại.Bạn nên luôn kiểm tra giá trị trả lại của cuộc gọi đọc và viết, để xem bạn có gặp phải bất kỳ lỗi nào không.

1

Những người khác nói rằng đường ống là đơn hướng, đó là điều tôi nghĩ lúc đầu. Nhưng trên thực tế đó là không phải những gì người đàn ông trang của tôi nói:

A read from fildes[0] accesses the data written to fildes[1] 
on a first-in-first-out (FIFO) basis and a read from 
fildes[1] accesses the data written to fildes[0] also on a 
FIFO basis. 

Tuy nhiên, điều này không có nghĩa là nếu phụ huynh đang viết để pipefd[0], thì đứa trẻ nên đọc từ pipefd[1], vì vậy bạn đang liên phía sai của ống với stdin của trẻ và stdout.

Từ trang hướng dẫn, có vẻ như bạn có thể làm điều này với một đường ống. Nhưng nó có thể là mã rõ ràng hơn để sử dụng hai.

Dường như bạn đang nghĩ về từng thành phần của pipefd như một đường ống riêng biệt, nhưng không phải như vậy.

+0

[Theo thông số POSIX] (http://pubs.opengroup.org/onlinepubs/009604599/functions/pipe.html) trên 'pipe', *" Nó không được chỉ định cho dù fildes [0] cũng mở cho viết và cho dù fildes [1] cũng mở để đọc. "* – Jason

+0

Vâng, nếu bạn muốn có một kênh hai chiều được bảo đảm, bạn cần' socketpair' hoặc một pseudoterminal. – zwol

Các vấn đề liên quan