0

我正在尝试创建一个简单的客户端/服务器程序,该程序允许客户端使用 TCP 套接字连接到服务器,然后允许用户从客户端向服务器端发出系统调用并将回复返回给用户。例如:

客户端问题:ls

服务器将在 /usr/bin 或 w/e 中找到 ls,然后使用 execve() 执行它

我还会有一些喜欢 lls 或 lmkdir 等的东西。它将在客户端发出系统调用。

问题是我的 execve() 似乎没有正确运行,因为实际上没有调用“ls”或任何其他命令。我之前只使用本地端(没有服务器或任何东西)完成了同样的程序,并且 execve() 工作正常。这是一些代码:

       pid = fork();

       if(pid){ // Child
        printf("child wait");
          pid = wait(&status);
          printf("Child dead\n");
       }else{ // Parent

          if(execPath){            

          execve(execPath, arglist, env);
          printf("Command Complete\n");

        }

       }

由于某种原因,PID 语句的子部分中的 printfs 根本没有执行。我不认为系统实际上会分叉一个进程。由于它是客户端/服务器类型的程序,我是否需要做一些特别的事情才能完成这项工作,还是应该完全一样?

谢谢

4

3 回答 3

2

确切地说,execve不分叉。它将当前图像替换为其参数指定的图像,并从其开始(即main())开始。它永远不会返回到您的原始程序。

您可能想system()在您的用例中使用。

于 2013-02-25T19:01:32.967 回答
1

由于子进程没有产生任何自己的子进程,因此wait()如果没有其他外部事件(例如中断调用的信号),调用不太可能返回。您应该让父进程等待子进程。

请注意,这fork()可能会失败,您应该考虑到这一点。另请注意,如果execve成功,它将不会返回。因此,如果要打印任何内容,它后面的 print 语句应该指示失败。

使用system()可能不会为您节省分叉,因为您可能希望将命令的输出定向到与已连接客户端关联的套接字。但是,您的代码缺少允许输出流向客户端的步骤。

switch ((pid = fork())) {
case -1:  /* todo: handle error */
          break;
case 0:   /* child */
          dup2(socket, 0); /* todo: check return value */
          dup2(socket, 1); /* todo: check return value */
          dup2(socket, 2); /* todo: check return value */
          close(socket);   /* todo: check return value */
          execve(...);
          /* todo: handle failure */
          exit(EXIT_FAILURE);
default:  /* parent */
          if (pid != waitpid(pid, 0, 0)) {
              /* todo: handle error */
          }
}
于 2013-02-25T19:49:06.547 回答
1

代码中有几个问题:

  • fork()返回父进程的pid,子进程返回零。所以 parent 运行 if 的真正分支。孩子运行 else 分支。交换那些评论。
  • 标准输出是行缓冲的。(\n)在等待之前添加新行printf。否则,在等待完成之前您看不到打印输出并且第二个printf正在呼叫中。
  • 确保孩子在错误情况下也会退出,否则孩子将运行父母的代码,而父母仍在等待孩子的退出。
  • execve如果成功则不返回。如果失败,它将返回。

因此,固定代码可能是这样的:

   pid = fork();

   if(pid){  // Parent
      printf("child wait\n");
      pid = waitpid(pid, &status, 0);
      printf("Child dead\n");
   }else{ // Child
      if(execPath){            
          execve(execPath, arglist, env);
          printf("execve failed!\n");
      }
      _exit(1);
   }

或者你可以使用system(3).

于 2013-02-25T20:52:35.527 回答