代码之家  ›  专栏  ›  技术社区  ›  Wolfat

无法从C中的管道执行读取?

  •  0
  • Wolfat  · 技术社区  · 7 年前

    我正在编写一个与应用程序交互的代码,涉及对应用程序的读写。下面是代码:第一个-即输入。c与第二个交互,即app。C

    //input.c    
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <string.h>
    #include <errno.h>
    
    #define WRITE 1
    #define READ 0
    
    void error(char* msg){
        perror(msg);
        exit(-1);
    }
    
    void got_here(char* msg){
        printf("Got_here:%s\n",msg);
    }
    
    int main(int argc, char** argv, char** envp){
        int fd_parent[2];
        int fd_child[2]; // for parent and child to write respectively
        if(pipe(fd_parent) < 0 | pipe(fd_child) < 0){
            error("Fail to create a pipe"); /// just an error-handle function
        }
        pid_t child = fork();
        if(child < 0){
            error("Fail to create a child"); 
        }
        else if(child == 0){
            dup2(fd_child[WRITE], STDOUT_FILENO);
            dup2(fd_parent[READ], STDIN_FILENO);
            close(fd_parent[WRITE]);
            close(fd_child[READ]);
            char str[100] = "./app";
            execve(str, argv,envp);
            close(fd_parent[READ]);
            close(fd_child[WRITE]);
            return 0;
        }
        else{
            close(fd_parent[READ]);
            close(fd_child[WRITE]);
    
            FILE* stream = fdopen(fd_child[READ], "r");
            FILE* stream_write = fdopen(fd_parent[WRITE], "w");
    
            char str[20];
            char menu[4] = "10\n";
            fread(str,sizeof(char), 20, stream); // Here is where the problem lies
            got_here("after read");  // it does not get here
            fwrite(menu, sizeof(char), 3, stream_write);
            fflush(stream_write);
    
            fclose(stream);
            fclose(stream_write);
            printf("Parent Done\n");
            return 0;
        }
    }
    

    以下是应用程序代码(我只包括较短代码的main):

    int main(int argc, char** argv, char** envp){
        char str[10];
        printf("- Select Menu -1\n");
        printf("1. Play Lotto\n");
        scanf("%s", str);
        return 0;
    }
    

    运行后,我的程序在 fread() 它应该在其中完成对应用程序的读写。有趣的是如果我省略了 scanf() printf() 在第二个程序中,它运行良好。我试着改变 fwrite fread 但问题仍然存在。我认为这是一个与缓冲区相关的问题,但我尝试与之交互的应用程序没有我的更改权限,因此我不能包括 fflush 或者别的什么。

    我的猜测是对的还是有其他解释?如何克服这个问题?

    1 回复  |  直到 7 年前
        1
  •  0
  •   Erki Aring    7 年前

    您可以使用 stdbuf 命令修改管道另一端程序的缓冲选项。要在C中执行此操作,可以编写:

    char str[100] = "./app";
    
    char **new_argv = malloc (sizeof (char *) * (argc + 9));
    new_argv[0] = "stdbuf";
    new_argv[1] = "-i";
    new_argv[2] = "0";
    new_argv[3] = "-o";
    new_argv[4] = "L";
    new_argv[5] = "-e";
    new_argv[6] = "L";
    new_argv[7] = str;
    memcpy (&new_argv[8], &argv[1], argc - 1);
    new_argv[argc + 8] = NULL;
    
    execvp ("stdbuf", new_argv);
    error ("execvp");
    

    或者,如果您真的不需要将家长的参数传递给孩子,那么:

    execlp ("stdbuf", "stdbuf", "-i", "0", "-o", "L", "-e", "L", "./app", NULL);
    error ("execlp");
    

    这个 stdbuf 命令使用LD\u PRELOAD加载库( libstdbuf.so )进入另一个程序。这个库完成了修改缓冲选项的技巧。您可以避免使用 stdbuf标准 并在exec()之前自行设置预加载选项。您也可以编写自己的库并预加载它。但是使用 stdbuf标准 如果有此命令可用,则可能是最简单的选项。

    另请参见 stdbuf source code

    下面是代码的完整修改示例:

    //input.c
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <string.h>
    #include <errno.h>
    
    #define WRITE 1
    #define READ 0
    
    void error (char *msg)
    {
        perror (msg);
        exit (-1);
    }
    
    void got_here (char *msg)
    {
        printf ("Got_here: %s\n", msg);
    }
    
    int main (int argc, char **argv, char **envp)
    {
        int fd_parent[2];
        int fd_child[2]; // for parent and child to write respectively
        pid_t child;
    
        if (pipe (fd_parent) < 0) {
            error ("pipe(fd_parent)");
        }
    
        if (pipe (fd_child) < 0) {
            error ("pipe(fd_child)");
        }
    
        child = fork ();
    
        if (child < 0) {
    
            error ("fork");
    
        } else if (child == 0) {
    
            dup2 (fd_child[WRITE], STDOUT_FILENO);
            dup2 (fd_parent[READ], STDIN_FILENO);
            close (fd_parent[WRITE]);
            close (fd_child[READ]);
    
            char str[100] = "./app";
    
            char **new_argv = malloc (sizeof (char *) * (argc + 9));
            new_argv[0] = "stdbuf";
            new_argv[1] = "-i";
            new_argv[2] = "0";
            new_argv[3] = "-o";
            new_argv[4] = "L";
            new_argv[5] = "-e";
            new_argv[6] = "L";
            new_argv[7] = str;
            memcpy (&new_argv[8], &argv[1], argc - 1);
            new_argv[argc + 8] = NULL;
    
            execvp ("stdbuf", new_argv);
            error ("execvp");
    
            close (fd_parent[READ]);
            close (fd_child[WRITE]);
    
            return 0;
    
        } else {
    
            close (fd_parent[READ]);
            close (fd_child[WRITE]);
    
            FILE *stream = fdopen (fd_child[READ], "r");
            FILE *stream_write = fdopen (fd_parent[WRITE], "w");
    
            char str[20];
            char menu[4] = "10\n";
            int res = fread (str, sizeof (char), 20, stream); // Here is where the problem lies
            printf ("res = %d\n", res);
            got_here ("after read");  // it does not get here
            fwrite (menu, sizeof (char), 3, stream_write);
            fflush (stream_write);
    
            fclose (stream);
            fclose (stream_write);
            printf ("Parent Done\n");
    
            return 0;
    
        }
    }
    
    推荐文章