Сетевое программирование на C с системными вызовами execve

Я пытаюсь создать простую программу клиент/сервер, которая позволяет клиенту подключаться к серверу с помощью сокета TCP, а затем позволяет пользователю выполнять системные вызовы с клиентской стороны на серверную и возвращать ответ пользователю. Например:

Проблемы клиента: ls

Сервер найдет ls в /usr/bin или w/e, а затем выполнит его с помощью 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");

        }

       }

По какой-то причине printfs в дочернем разделе инструкции PID вообще не выполняются. Я не думаю, что система на самом деле когда-либо разветвляет процесс. Есть ли что-то особенное, что мне нужно сделать, чтобы эта работа работала, поскольку это программа типа клиент/сервер, или она должна работать точно так же?

Спасибо


person Matt Hintzke    schedule 25.02.2013    source источник
comment
Покажите нам execPath и arglist.   -  person cnicutar    schedule 25.02.2013
comment
Это вряд ли будет вашей проблемой, но вам нужно проверить, возвращает ли fork() -1, указывая на ошибку (например, слишком много процессов в вашей системе).   -  person Adam Rosenfield    schedule 25.02.2013
comment
Ребенок не может ждать родителей. Родитель может подождать ребенка.   -  person jxh    schedule 25.02.2013
comment
Родитель управляет первой веткой. А дочерняя отвечает за else-ветку. Вы должны исправить эти комментарии кода.   -  person SKi    schedule 26.02.2013


Ответы (3)


точно, execve не разветвляется. Он заменяет текущее изображение изображением, указанным в качестве его аргумента, и начинает с его начала (т. е. main()). Он никогда не вернется к исходной программе.

Вы, вероятно, захотите использовать system() в своем случае использования.

person mity    schedule 25.02.2013

В коде есть несколько проблем:

  • fork() возвращает pid для родителя и ноль для дочернего элемента. Итак, parent запускает истинную ветвь if. И ребенок запускает другую ветвь. Поменяйте местами эти комментарии.
  • Стандартный вывод буферизуется строкой. Добавьте новую строку (\n) в printf перед ожиданием. В противном случае вы не увидите распечатку до завершения ожидания и вызова 2-го 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).

person SKi    schedule 25.02.2013

Поскольку дочерний процесс не породил собственных дочерних процессов, маловероятно, что вызов wait() вернется без какого-либо другого внешнего события (например, сигнала, прерывающего вызов). Вместо этого вы должны заставить родителя ждать дочерний процесс.

Обратите внимание, что fork() может дать сбой, и вы должны учитывать это. Также обратите внимание, что если execve завершится успешно, он не вернется. Таким образом, оператор печати после него должен указывать на ошибку, если он вообще что-либо печатает.

Использование 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 */
          }
}
person jxh    schedule 25.02.2013