如何通过C中的命令行参数传递管道和其他值?

时间:2011-05-08 16:09:49

标签: c exec pipe

我正在尝试创建几个程序,第一个程序启动所有必需的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打印到stdout,所以我确定它们有一个值。至于知道程序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”)替换它们,它们会在子页面中显示为参数。但在这种情况下,NOTHING正在从程序3打印。

3 个答案:

答案 0 :(得分:2)

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

因此,要将信号量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()返回,则失败。您无需测试其返回值。


来自评论:

  

[我]只是简单地删除相关部分[...] [我]不确定你对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 :(得分:-1)

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

答案 2 :(得分:-1)

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