2008-09-16 55 views
7

Tôi nên chạy chương trình khác từ bên trong chương trình C của mình như thế nào? Tôi cần để có thể ghi dữ liệu vào STDIN của chương trình được khởi chạy (và có thể đọc từ đó là STDOUT)Thực hiện chương trình từ bên trong chương trình C

Tôi không chắc đây có phải là hàm C chuẩn hay không. Tôi cần giải pháp mà nên làm việc dưới Linux.

+0

Đây là một bản sao của câu hỏi này: http://stackoverflow.com/questions/17140/how-do-you-spawn-another-process-in-c –

Trả lời

17

Bạn muốn sử dụng popen. Nó cung cấp cho bạn một đường ống một chiều mà bạn có thể truy cập stdin và stdout của chương trình.

popen là tiêu chuẩn trên hiện đại unix và unix-like OS, trong đó Linux là một :-)

Loại

man popen 

trong một thiết bị đầu cuối để đọc thêm về nó.

EDIT

popen sản xuất ống một chiều hoặc hai chiều phụ thuộc vào việc thực hiện. Trong LinuxOpenBSD, popen sản xuất các ống một chiều, chỉ đọc hoặc chỉ ghi. Trên OS X, FreeBSDNetBSDpopen sản xuất ống hai chiều.

+1

Lưu ý rằng đó là stdin _or_ stdout, không phải cả hai cùng một lúc. – wnoise

+0

Trong triển khai hiện đại, nó là stdin và stdout. Các đường ống được phép là hai chiều, mặc dù theo truyền thống nó là một chiều. – freespace

+0

"man popen" trên Ubuntu 9.04 nói "Vì một đường ống theo định nghĩa một chiều, đối số kiểu có thể chỉ định chỉ đọc hoặc viết, không phải cả hai". – nobar

0

Tôi nghĩ rằng bạn có thể sử dụng

freopen

cho việc này.

7
  1. Tạo hai ống với pipe(...), một cho stdin, một cho stdout.
  2. fork(...) quy trình.
  3. Trong quy trình con (nơi fork(...) trả lại 0) dup (...) các đường ống đến stdin/stdout.
  4. exec[v][e] tệp chương trình được bắt đầu trong quá trình con.
  5. Trong quá trình cha mẹ (một trong những nơi fork) trả về PID của đứa trẻ) làm một vòng lặp mà đọc từ của stdout (select(...) hoặc poll(...), read(...)) vào một bộ đệm trẻ em, cho đến khi trẻ chấm dứt (waitpid(...)).
  6. Cuối cùng cung cấp cho trẻ với đầu vào theo số stdin nếu có yêu cầu.
  7. Khi hoàn thành close(...) các đường ống.
4

Tôi không đồng ý với Nathan Fellman - các câu hỏi khác không phải là một bản sao của này, mặc dù đối tượng có liên quan.

Đối với giao tiếp đơn hướng đơn giản, popen() là một giải pháp tốt. Nó không được sử dụng cho truyền thông hai hướng, mặc dù.

IMO, imjorge (Jorge Ferreira) đưa ra hầu hết câu trả lời (80%?) Cho giao tiếp hai chiều - nhưng bỏ qua một vài chi tiết chính.

  1. Điều quan trọng là quá trình cha mẹ đóng đầu đọc của đường ống được sử dụng để gửi thư đến quá trình con.
  2. Điều quan trọng là quá trình con đóng đầu ghi của đường ống được sử dụng để gửi tin nhắn đến tiến trình con.
  3. Điều quan trọng là quá trình cha mẹ đóng đầu ghi của đường ống được sử dụng để gửi thư đến quy trình gốc.
  4. Điều quan trọng là quá trình con đóng đầu đọc của đường ống được sử dụng để gửi tin nhắn đến quy trình gốc.

Nếu bạn không đóng đầu chưa sử dụng của ống, bạn sẽ không nhận được hành vi hợp lý khi một trong các chương trình chấm dứt; ví dụ, đứa trẻ có thể đọc từ đầu vào tiêu chuẩn của nó, nhưng trừ khi kết thúc viết của ống được đóng trong đứa trẻ, nó sẽ không bao giờ nhận được EOF (không byte từ đọc) vì nó vẫn có đường ống mở và hệ thống nghĩ rằng đôi khi có thể đi xung quanh để viết cho đường ống đó, mặc dù nó hiện đang treo chờ đợi một cái gì đó để đọc từ nó.

Quy trình viết nên xem xét xem có xử lý tín hiệu SIGPIPE được cung cấp khi bạn viết trên đường ống không có quy trình đọc không.

Bạn phải nhận thức được dung lượng ống (phụ thuộc vào nền tảng và có thể ít nhất 4KB) và thiết kế chương trình để tránh bế tắc.

8

Tôi đã viết một số mã C ví dụ cho người khác trong khi quay lại cho biết cách thực hiện việc này. Ở đây nó là dành cho bạn:

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

void error(char *s); 
char *data = "Some input data\n"; 

main() 
{ 
    int in[2], out[2], n, pid; 
    char buf[255]; 

    /* In a pipe, xx[0] is for reading, xx[1] is for writing */ 
    if (pipe(in) < 0) error("pipe in"); 
    if (pipe(out) < 0) error("pipe out"); 

    if ((pid=fork()) == 0) { 
    /* This is the child process */ 

    /* Close stdin, stdout, stderr */ 
    close(0); 
    close(1); 
    close(2); 
    /* make our pipes, our new stdin,stdout and stderr */ 
    dup2(in[0],0); 
    dup2(out[1],1); 
    dup2(out[1],2); 

    /* Close the other ends of the pipes that the parent will use, because if 
    * we leave these open in the child, the child/parent will not get an EOF 
    * when the parent/child closes their end of the pipe. 
    */ 
    close(in[1]); 
    close(out[0]); 

    /* Over-write the child process with the hexdump binary */ 
    execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL); 
    error("Could not exec hexdump"); 
    } 

    printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid); 

    /* This is the parent process */ 
    /* Close the pipe ends that the child uses to read from/write to so 
    * the when we close the others, an EOF will be transmitted properly. 
    */ 
    close(in[0]); 
    close(out[1]); 

    printf("<- %s", data); 
    /* Write some data to the childs input */ 
    write(in[1], data, strlen(data)); 

    /* Because of the small amount of data, the child may block unless we 
    * close it's input stream. This sends an EOF to the child on it's 
    * stdin. 
    */ 
    close(in[1]); 

    /* Read back any output */ 
    n = read(out[0], buf, 250); 
    buf[n] = 0; 
    printf("-> %s",buf); 
    exit(0); 
} 

void error(char *s) 
{ 
    perror(s); 
    exit(1); 
} 
Các vấn đề liên quan