2010-06-20 114 views
3

我已准备的程序使用管道它将模拟壳(CMD)接口有该程序的两个版本: 1.使用一个管(使用从父管道儿童通信) 2.使用双管道(使用从父母到孩子和从父母到父母的两条管道进行通信)C:GOT卡住DUP2():-(

因此,第一个程序提供了所需的界面并且工作方式如何,但我无法达到相同结果(接口)在第二个程序中(使用dup2()和类似的)

因此,我接力你的帮助,并把两个代码放在下面

BS:您可以编辑和使用这些命令尝试用同样的方式这两个程序:

$ GCC prog1.c的-o PROG1

接下来让我们来运行:

$ ./prog1

接下来让我们来运行新的终端,并尝试写一些数据INPUT.TXT:

$呼应PWD> input.txt中

,然后看结果在第一终端。

(这工作正常第一个节目,但我需要得到这个工作的机智在第二个方案相同的接口)

的第一个程序代码(工作正常):

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/stat.h> 

void do_child(int data_pipe[]) { 
    int c; 
    int rc; 
    close(data_pipe[1]); 

    dup2(data_pipe[0], 0); /* This string provides the desired interface of the program */ 

    char* cmd[] = { "bash", (char *)0 }; 
    execvp("bash", cmd); 

    while ((rc = read(data_pipe[0], &c, 1)) > 0) 
    { 
     putchar(c); 
    } 
    exit(0); 
} 

void do_parent(int data_pipe[]) 
{ 
    int c; 
    int rc; 
    FILE *in; 

    close(data_pipe[0]); 

    while (1) 
    { 
     in = fopen("input.txt", "r"); 
     while ((c = fgetc(in)) > 0) 
     { 
      rc = write(data_pipe[1], &c, 1); 
      if (rc == -1) 
      { 
       perror("Parent: write"); 
       close(data_pipe[1]); 
       exit(1); 
      } 
     } 
     fclose(in); 
    } 
    close(data_pipe[1]); 
    exit(0); 
} 

int main(int argc, char* argv[]) 
{ 
    int data_pipe[2]; 
    int pid; 
    int rc; 

    umask(0); 
    mknod("input.txt", S_IFIFO|0666, 0); 

    rc = pipe(data_pipe); 
    if (rc == -1) 
    { 
     perror("pipe"); 
     exit(1); 
    } 
    pid = fork(); 
    switch (pid) 
    { 
    case -1: 
     perror("fork"); 
     exit(1); 
    case 0: 
     do_child(data_pipe); 
    default: 
     do_parent(data_pipe); 
    } 
    return 0; 
} 

CODE第二程序的(需要加以纠正一点点):

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/stat.h> 

/* Original version got from http://www.iakovlev.org */ 

int parent_to_child[2]; 
int child_to_parent[2]; 

void do_parent() 
{ 
    int c; 
    char ch; 
    int rc; 
    FILE *in; 

    close(child_to_parent[1]); /* we don't need to write to this pipe. */ 
    close(parent_to_child[0]); /* we don't need to read from this pipe. */ 

    while (1) 
    { 
     in = fopen("input.txt", "r"); 
     while ((c = fgetc(in)) > 0) { 
      ch = (char)c; 
      /* write to child */ 
      rc = write(parent_to_child[1], &ch, 1); 
      if (rc == -1) { 
       perror("child: write"); 
       close(child_to_parent[0]); 
       close(parent_to_child[1]); 
       exit(1); 
      } 
      /* read back from child */ 
      rc = read(child_to_parent[0], &ch, 1); 
      c = (int)ch; 
      if (rc <= 0) { 
       perror("parent: read"); 
       close(child_to_parent[0]); 
       close(parent_to_child[1]); 
       exit(1); 
      } 
      putchar(c); 
     } 
     fclose(in); 
    } 
    close(child_to_parent[0]); 
    close(parent_to_child[1]); 
    exit(0); 
} 

void do_child() 
{ 
    int c; 
    char ch; 
    int rc; 

    close(parent_to_child[1]); /* we don't need to write to this pipe. */ 
    close(child_to_parent[0]); /* we don't need to read from this pipe. */ 

    //dup2(parent_to_child[0], STDIN_FILENO); 
    //dup2(child_to_parent[1], STDOUT_FILENO); 

    /* Some dup2() routines must be added here 
    to get this working as the first program above */ 

    char* cmd[] = { "bash", (char *)0 }; 
    execvp("bash", cmd); 

    while (read(parent_to_child[0], &ch, 1) > 0) { 
     c = (int)ch; 
     ch = (char)c; 
     putchar(ch); 
     rc = write(child_to_parent[1], &ch, 1); 
     if (rc == -1) { 
      perror("child: write"); 
      close(parent_to_child[0]); 
      close(child_to_parent[1]); 
      exit(1); 
     } 
    } 
    close(parent_to_child[0]); 
    close(child_to_parent[1]); 
    exit(0); 
} 

int main(int argc, char* argv[]) 
{ 
    int pid; 
    int rc; 

    umask(0); 
    mknod("input.txt", S_IFIFO|0666, 0);  

    rc = pipe(parent_to_child); 
    if (rc == -1) { 
     perror("main: pipe parent_to_child"); 
     exit(1); 
    } 

    rc = pipe(child_to_parent); 
    if (rc == -1) { 
     perror("main: pipe child_to_parent"); 
     exit(1); 
    } 

    pid = fork(); 
    switch (pid) { 
    case -1: 
     perror("main: fork"); 
     exit(1); 
    case 0: 
     do_child(); 
    default: 
     do_parent(); 
    } 
    return 0; 
} 
+0

我不知道你为什么标题为 “ANSI C” 专。在标准ANSI C库中没有'dup2'这样的函数。 – AnT 2010-06-20 20:51:09

回答

0

主要的区别就在这里:

while ((c = fgetc(in)) > 0) { 
     ch = (char)c; 
     /* write to child */ 
     rc = write(parent_to_child[1], &ch, 1); 
     /* .... */ 
     /* read back from child */ 
     rc = read(child_to_parent[0], &ch, 1); 
     /* .... */ 
     putchar(c); 
    } 

正如我懒得编译/测试你的,我会简单地推测,家长被挡在读()。因为其他方面(bash在子进程中)不能保证回显每个书面字符。或者甚至可能决定打印不止一个字符,而您的代码无法处理。

在这种情况下,您必须poll()来查看是否有东西需要读取。或者用fcntl(F_SETFL)在child_to_parent [0]上设置O_NONBLOCK标志,当errno == EAGAIN时,只需跳过read()分支。并且还有字符可以读取。

Edit1。 BTW我完全错过了一部分:你在do_parent()循环必须使用的两种child_to_parent[0]in民调(),因为对方可能会写一些东西(阅读()将不会阻塞),即使你不写()任何角色。

0

感谢你似乎我得到它的工作。

所以,在这里被更新do_parent代码:

void do_parent() 
{ 
    int c; 
    char ch; 
    int rc; 
    FILE *in; 

    struct pollfd fds[2]; 
    int pol_ret; 

    fds[0].fd = child_to_parent[0]; 

    close(child_to_parent[1]); /* we don't need to write to this pipe. */ 
    close(parent_to_child[0]); /* we don't need to read from this pipe. */ 

    while (1) 
    { 
     in = fopen("input.txt", "r"); 
     fds[1].fd = fileno(in); 
     pol_ret = poll(fds, 2, 500); 

     while ((c = fgetc(in)) > 0) { 
      ch = (char)c; 
      /* write to child */ 
      rc = write(parent_to_child[1], &ch, 1); 
      if (rc == -1) { 
       perror("child: write"); 
       close(child_to_parent[0]); 
       close(parent_to_child[1]); 
       exit(1); 
      } 
      /* read back from child */ 
      if (fds[0].revents & POLLIN) 
      { 
       rc = read(child_to_parent[0], &ch, 1); 
       c = (int)ch; 
       if (rc <= 0) { 
        perror("parent: read"); 
        close(child_to_parent[0]); 
        close(parent_to_child[1]); 
        exit(1); 
       } 
       putchar(c); 
      } 
     } 
     fclose(in); 
    } 
    close(child_to_parent[0]); 
    close(parent_to_child[1]); 
    exit(0); 
} 

而且我已经加入到这个do_child():

dup2(parent_to_child[0], STDIN_FILENO); 
+0

不幸的是,这个问题部分解决了。这种方式不适用于Windows(通过Cygwin编译)。如果cygwin1.dll存在于程序所在的相同目录中,则结果与以前相同。在Cygwin shell中,一切工作正常。 – 0xDEFACE 2010-06-21 13:41:36