-1

下面的程序既不将程序加载到子进程也不打印“之前”和“之后”。但是 ps aux 显示了进程的创建(但没有加载 args0 程序)。我正在使用定义为套接字对的 PI​​PE。args0[] 保存子程序的可执行名称,args1[] 保存子程序的名称。args2 和 args3 是预定义的值,不会更改,应作为参数发送给子级。您可以假设 char args2[] = "10" --> 用户输入(数字)并转换为字符串。我只是不明白为什么至少 printf("before") 没有打印出来。我读到了 fflush 并将 \n 放在每个 printf 上,我做到了。所以到目前为止,我的程序中的所有内容都已正确打印。

我真的很感激你的回复。

char args2[];
char args3[];
//creating pipe
int forkk(pipes *myPipe, server_message *m, char args0[],char args1[]) {
pid_t cpid;

//pipe passed myPipe[i]
if (PIPE(myPipe->fd) == -1) {
    perror("pipe error\n");
    return -1;
}
 fork();
 cpid=getpid();
if (cpid == -1) {
    perror("fork error\n");
    return -1;
}
if (cpid) {
    close(myPipe->fd[1]);
    return 1;//closing one end of parent

} else {

    for (int i = 3; i <= myPipe->fd[0]; i++) {
        close(i);
    }

    dup2(myPipe->fd[1], 0); //redirecting stdin of child
    dup2(myPipe->fd[1], 1); //redirecting stdout of child
    close(myPipe->fd[1]);
    myPipe->cpid = cpid;
    char *newargs[3];
    newargs[0]=args1;
    newargs[1]=args2;
    newargs[2]=args3;
    printf("before\n");
    //fflush(stdout);
    execv(args0,newargs);
    printf("after execv\n");
    write(myPipe->fd[0], &m, sizeof(server_message));  //send the server_msg immediately (pass an array or msg)

}
    return 2;

}

void main(){
....
scanf("%d %d", &width, &height);
sprintf(args2,"%d",height); //converting into to string
sprintf(args3,"%d",width);
char *args0 = "./prey";
char *args1 = "prey";
int r= forkk(&myPipes[2], &msg, args0,args1);

}

我无法发布整个代码,因为它很长并且需要解释。我很可能在指针分配方面遇到问题,我错误地认为这是正确的方法。非常感谢任何帮助

4

1 回答 1

0

(剧透:你else名字不好的分支forkk永远不会被占用!)

仔细阅读execv(3)的文档。您应该提供一个NULL终止的数组。

execv()、execvp() 和 execvpe() 函数提供了一个指向以 null 结尾的字符串的指针数组,这些字符串表示新程序可用的参数列表。按照惯例,第一个参数应该指向与正在执行的文件关联的文件名。 指针数组必须以空指针终止

所以你至少应该编码:

char *newargs[4];
newargs[0]=args1;
newargs[1]=args2;
newargs[2]=args3;
newargs[3] = NULL; // mandatory last NULL pointer
execv(args0,newargs);

顺便说一句,第一个参数通常应该是程序名称。所以你真的想要:

char *newargs[5];
newargs[0] = args0;
newargs[1]=args1;
newargs[2]=args2;
newargs[3]=args3;
newargs[4] = NULL; // mandatory last NULL pointer
execv(args0,newargs);

文件还说

exec() 函数仅在发生错误时返回。

所以在大多数情况下,没有必要在这里继续,因为execv如果成功就不会返回。但是,您需要捕获失败。我推荐你之后execv

perror(arg0); // or perhaps perror("execv");
exit(EXIT_FAILURE);

你的write(myPipe->fd[0], &m, sizeof(server_message));气味非常难闻。我认为(仅)在execv失败时这样做没有意义

顺便说一句,使用strace(1)您可能会发现这样的错误(缺少 的终止NULL 指针execv)。

最后,您应该始终保留fork(2)的结果。看到这个。所以替换:

 fork(); // WRONG
 cpid=getpid(); // always positive!

cpid = fork();

当然,你需要处理这三种情况:(cpid== -1你忘了处理!)cpid== 0,,,cpid> 0

再次仔细阅读getpid(2)

getpid() 返回调用进程的进程 ID (PID)。

和(关于getpid& getppid):

这些功能总是成功的

所以getpid 永远不要返回 0 (这就是为什么你的else分支在你forkk的名字不好的函数中,包含execvp,从不运行)。另见凭证(7)

void main() 的也是错的。main应该返回一个int. 您通常将其定义为int main(int argc, char**argv)...

PS。养成仔细阅读您正在使用的每个函数的文档的习惯。

forkk的名字很糟糕,与非常重要的名字太相似了fork

于 2018-03-16T18:00:24.580 回答