Я постараюсь быть максимально конкретным с моей проблемой.Моя цель - реализовать два сокета (клиент / сервер);клиент должен отправить серверу команду awk + несколько строк ввода.Сервер должен выполнить команду awk с заданным вводом и отослать клиенту каждую строку стандартного вывода awk и каждую строку стандартного ввода awk, соединенную со строкой «ERRLINEi» (i = номер строки).
Я спросил, как это сделать, так как я полностью потерялся, и я получил хороший совет, чтобы использовать fork, execl, pipe и dup2.Поэтому я попытался записать это:
void run_awk(char *command, char *out, char *err){
int in_pipe[2]; //send input string from parent to child --> input
int out_pipe[2]; //receive awk's stdout from child --> send back to client
int err_pipe[2]; //receive awk's stderr from child --> write on fd 4, send back to client with errline
pid_t p;
if((pipe(in_pipe)+pipe(out_pipe)+pipe(err_pipe)) < 0) syscallerror("pipe");
if((p = fork()) < 0) syscallerror("fork");
if(p > 0){
close(in_pipe[0]); // Close reading end of first pipe
close(out_pipe[1]); // Close writing end of second pipe
write(in_pipe[1], command, strlen(command)+1);
printf("parent process %d: sent input %s\n", getpid(), command);
close(in_pipe[1]);
// Wait for child to send out and err
wait(NULL);
char s_out[301];
char s_err[301];
int n = read(out_pipe[0], s_out, 300);
int k = read(err_pipe[0], s_err, 300);
if(n > 0) printf("parent %d: received output %s\n", getpid(), s_out);
if(k > 0) printf("parent %d: received error %s\n", getpid(), s_err);
close(out_pipe[0]);
close(err_pipe[0]);
close(err_pipe[1]);
}
else if(p == 0){
close(in_pipe[1]); // Close writing end of first pipe
// Read a string using first pipe
char buf[300];
read(in_pipe[0], buf, 300);
printf("child %d: received input %s\n", getpid(), buf);
// Close all reading ends
close(in_pipe[0]);
close(out_pipe[0]);
close(err_pipe[0]);
dup2(out_pipe[1], 1); //set out_pipe[1] as stdout
dup2(err_pipe[1], 2); //set err_pipe[1] as stderr
close(err_pipe[1]);
close(out_pipe[1]);
execl("usr/bin/awk", "awk", buf, (char *)0); //at this point awk's
exit(0); //out and err should be redirected to the pipes
}
}
Но это не работает.Обратите внимание, что эта функция вызывается в цикле while, который повторяется до тех пор, пока новые входные строки не будут получены от клиента.Я на самом деле не понимал, почему, поэтому я поставил инструкцию printf перед вызовом функции (в основной функции, где вызывается run_awk ()), и в результате этого run_awk () вызывался несколько раз из одного и того же процесса с одним и тем же вводом,
Примечание: параметры my * out и * err должны использоваться для хранения результатов awk.Я оставил их неиспользованными, так как я просто хотел посмотреть, что делает моя программа.
ОБНОВЛЕНИЕ Я понял некоторые ошибки в моем коде.Я вернулся к основной функции, но у меня все еще есть проблемы.Практически мне нужно сделать следующее: отправить одну команду (с разумным синтаксисом awk) от родителя к потомку (и я достиг этого), а затем заставить ребенка читать строки ввода (произвольный текст) одну за другой, из stdin, что позволяет execlчтобы работать так:
execl("/usr/bin/awk", "awk", command, (char *)0)
Мой новый код:
if((t_fd = accept(l_fd, (struct sockaddr *)NULL, NULL)) < 0) sockerror(2, 0); //accept connection from client
recv(t_fd, &com_len, sizeof(int), 0); //receive command length
command = malloc(com_len+1);
rbytes = recv(t_fd, command, com_len, 0); //receive command
command[rbytes] = '\0';
printf("Received command: %s\n", command);
if((pipe(in_pipe)+pipe(out_pipe)+pipe(err_pipe)) < 0) syscallerror("pipe"); //init pipes
bool check = true;
while(recv(t_fd, &inp_len, sizeof(int), 0) > 0){ //receive single input line length - loop while there are lines to read
memset(input, 0, inp_len+1);
recv(t_fd, input, inp_len, 0); //receive input line
if((p = fork()) < 0) syscallerror("fork");
if(p > 0){
close(in_pipe[0]); // Close reading end of first pipe
if(check){ //this makes the server write the command in the pipe just once
write(in_pipe[1], command, strlen(command));
check = false;
}
write(in_pipe[1], input, strlen(input)); //write the input line
//close(in_pipe[1]); //I can't close it because other lines will be sent in the loop
close(out_pipe[1]);
close(err_pipe[1]);
int n = read(out_pipe[0], out, 300); //read should block until child has produced output (you can assume it will always produce it)
int k = read(err_pipe[0], err, 300);
if(n > 0) printf("parent %d: received output %s\n", getpid(), out);
if(k > 0) printf("parent %d: received error %s\n", getpid(), err);
close(out_pipe[0]);
close(err_pipe[0]);
memset(out, 0, 301);
memset(err, 0, 301);
}
else{
close(in_pipe[1]); // Close writing end of first pipe
char com[300]; // Read command using first pipe
read(in_pipe[0], com, 300);
// Close all reading ends
close(out_pipe[0]);
close(err_pipe[0]);
dup2(in_pipe[0], 0); //set correct file descriptors
dup2(out_pipe[1], 1);
dup2(err_pipe[1], 2);
close(in_pipe[0]);
close(err_pipe[1]);
close(out_pipe[1]);
if(execl("/usr/bin/awk", "awk", com, (char *)0) < 0) syscallerror("execl");
exit(0);
}
}
close(in_pipe[1]);
kill(p, SIGKILL);
Если вы видите какие-либо неинициализированные переменные, это потому, что они объявлены вне этого цикла.Как я могу решить это?