【问题标题】:How do I pass pipes and other values through command line parameters in C?如何通过 C 中的命令行参数传递管道和其他值?
【发布时间】:2011-08-21 04:17:48
【问题描述】:

我正在尝试创建几个程序,其中第一个程序启动所有必需的 IPC 元素。我遇到的问题是使用第一个值执行辅助程序。我尝试了以下方法:

int sem_id = semget (key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
if (pipe (pipe1)){
    printf("Error: %s",strerror(errno));
    exit(1);
}

if(execl("/home/tropix/program-3","/home/tropix/program-3", sem_id, shmid, pipe1, (char*)0) == 0){
    fprintf(stderr, "File Execution of program 3 failed.\n");
    exit(1);
}

程序 3 没有执行,所以我的 execl 语句显然有问题。如果我删除变量 sem_id、shmid 和 pipe2,它就会运行。

感谢您的任何建议。

编辑:添加了用于创建 shmid 和 sem_id 的语句。我可以将这些 int 打印到标准输出,所以我确信它们是有价值的。至于知道程序3是否正在执行,请参见程序3:

main(int argc, char *argv[]){
    int x;
    printf("Number of args = %d", argc);
    for(x=0;x<argc;x++){
    printf("arg#: %d, %s\n",x,argv[x]);
    }
}

另一个注意事项:我已经编译了程序 3。如果我删除 execl 参数并将它们替换为带引号的单词(“test”),它们会在子页面中显示为参数。但在这种情况下,程序 3 中没有打印任何内容。

【问题讨论】:

    标签: c exec pipe


    【解决方案1】:

    程序的参数必须都是字符串。

    因此,要将信号量 ID、共享内存 ID 和文件描述符传递给执行程序,您需要调用程序代码将数字转换为字符串,然后执行程序将字符串转换回数字,然后使用适当的。

    您的代码没有显示 'pipe2'...我假设它是一个简单的 int,但如果它是一个数组(如 pipe1 是),那么您需要用 0 或1 获取相关文件描述符:

    char shmarg[20];
    char semarg[20];
    char piparg[20];
    int semid = semget (key1, 4, IPC_CREAT | 0666);
    int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
    int pipe1[2];
    const char *cmd = "/home/tropix/program-3";
    
    if (pipe(pipe1))
    {
        printf("Failed to create pipe: %s\n", strerror(errno));
        exit(1);
    }
    
    snprintf(shmarg, sizeof(shmarg), "%d", shmid);
    snprintf(semarg, sizeof(semarg), "%d", semid);
    snprintf(piparg, sizeof(piparg), "%d", pipe2);
    
    execl(cmd, cmd, semarg, shmarg, piparg, (char*)0);
    fprintf(stderr, "File Execution of program 3 failed.\n");
    exit(1);
    

    不清楚为什么要创建pipe1;你需要用它做适当的管道。如果execl() 返回,则失败。你不需要测试它的返回值。


    来自cmets:

    [I'm] 只是为了简单起见删除了相关部分 [...] [Im] 不确定您所说的 pipe1 的“适当管道”是什么意思?你能告诉我应该怎么做,或者让我参考一些关于如何初始化管道并将其传递给下一个文件的信息吗?我意识到在需要它的程序中创建管道可能是一个更好的选择,但在这种情况下,需要在程序 1 中对其进行初始化。

    问题的简单性是个好主意...

    我假设在对pipe()execl() 的调用之间,有一个fork() 被省略了。否则,pipe() 毫无意义。

    据推测,创建管道的目的是让子进程与父进程对话,或者让父进程与子进程对话。有双向管道,但它们既不是标准的也不是便携式的;因此,我假设您有一个常规的单向管道。由于您将文件描述符编号作为参数传递给子节点,因此我们不会为子节点重定向标准输入或标准输出 - 这是您经常(但不总是)使用管道执行的操作。

    因此,您修改后的代码可能是(删除空白行以避免滚动条):

    char shmarg[20];
    char semarg[20];
    char piparg[20];
    int semid = semget(key1, 4, IPC_CREAT | 0666);
    int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
    int pipe1[2];
    const char *cmd = "/home/tropix/program-3";
    if (pipe(pipe1))
    {
        printf("Failed to create pipe: %s\n", strerror(errno));
        exit(1);
    }
    pid_t pid = fork();
    if (pid < 0)
        err_exit("Failed to fork");
    else if (pid > 0)
    {
        /* Do parental things */
        close(pipe1[0]);
        ...write to pipe1[1]...
    }
    else
    {
        /* Do childish things */
        /* Assuming child is reading from pipe */
        close(pipe1[1]);
        snprintf(shmarg, sizeof(shmarg), "%d", shmid);
        snprintf(semarg, sizeof(semarg), "%d", semid);
        snprintf(piparg, sizeof(piparg), "%d", pipe1[0]);
        execl(cmd, cmd, semarg, shmarg, piparg, (char*)0);
        fprintf(stderr, "File Execution of program 3 failed.\n");
        exit(1);
    }
    

    显然,如果管道由父级读取并由子级写入,则需要兼顾关闭和指定的文件描述符编号。

    几乎总是,您最终会关闭从pipe() 返回的两个文件描述符中的至少一个。如果将管道重定向到标准输入或标准输出,通常使用dup2() 复制管道的相应端,然后关闭从pipe() 返回的两个文件描述符。由于所有这些都在弄乱管道,因此通俗地称为管道。

    【讨论】:

    • 代码中的所有管道都是管道1,为了简单起见,我只是剪掉了相关部分,所以请原谅错误。但是您的回答完全有道理,但我不确定您对 pipe1 的“适当管道”是什么意思?你能告诉我应该怎么做,或者让我参考一些关于如何初始化管道并将其传递给下一个文件的信息吗?我意识到在需要它的程序中创建管道可能是一个更好的选择,但在这种情况下,需要在程序 1 中对其进行初始化。非常感谢您的输入,顺便说一句
    • 尝试了几件事后,我明白了。感谢您的宝贵时间!
    【解决方案2】:

    你怎么知道program-3 没有运行? execl 调用看起来没问题,前提是 /home/tropix/program-3 是一个可执行程序。您能否提供sem_idshmidpipe2 的定义?

    【讨论】:

      【解决方案3】:

      我将假设 sem_id、shmid 和 pipe2 不是以空值结尾的字符串。您必须将它们转换为它们,因为它们是命令的参数,就像它们在命令行上一样。

      【讨论】:

      • 如果我在它们周围加上引号,我可以传递字符串,但我需要传递它们包含的值。在这种情况下,int int 指针。
      • @Josh 是的,但那是你的问题。 execl(3) 只接受以空字符结尾的字符串。您不能以这种方式将任意类型传递给程序。 Execl 作为命令传递给 shell。
      猜你喜欢
      • 2012-04-06
      • 1970-01-01
      • 2011-02-12
      • 2017-09-11
      • 1970-01-01
      • 2021-08-24
      • 1970-01-01
      • 2017-04-14
      • 2013-08-10
      相关资源
      最近更新 更多