如何在 C 中使用管道和 dup2
How to use pipe and dup2 in c
我必须在 c 中使用管道模拟此命令: echo "" |公元前-lq。
进程A必须读取一个字符串并发送给进程B;
进程B执行“bc -lq”命令,returns结果给A.
代码是这样的,但是我不明白为什么它不起作用;特别是,“bc”命令似乎无法从标准输入中读取表达式。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define LEGGI(stringa) if(scanf("%s", stringa) == 0) \
{ \
perror("Impossibile leggere la stringa"); \
exit(EXIT_FAILURE); \
} \
void closePipe(int pipeFd);
void Dup2(int pipeTempFd, int fd);
void Write(int pipeTempFd, char stringa[], int n);
void Read(int pipeTempFd, char stringa[], int n);
int main()
{
char stringa[N];
LEGGI(stringa);
int pipeFd[2];
int pRicezioneFd[2];
if(pipe(pipeFd) == -1 || pipe(pRicezioneFd) == -1)
{
perror("impossibile eseguire la pipe");
exit(EXIT_FAILURE);
}
if(strncmp(stringa, "exit", N) != 0)
{
pid_t processPid;
if((processPid = fork()) == 1)
{
perror("impossibile eseguire la fork");
exit(EXIT_FAILURE);
}
if(processPid != 0)
{
closePipe(pipeFd[0]);
closePipe(pRicezioneFd[1]);
printf("operazione: %s\n", stringa);
Write(pipeFd[1], stringa, N);
closePipe(pipeFd[1]);
read(pRicezioneFd[0], stringa, N);
closePipe(pRicezioneFd[0]);
if(wait(NULL) == -1)
{
perror("Impossibile eseguire la wait");
exit(EXIT_FAILURE);
}
printf("%s\n", stringa);
}
else
{
closePipe(pipeFd[1]);
closePipe(pRicezioneFd[0]);
Dup2(pipeFd[0], 0);
Dup2(pRicezioneFd[1], 1);
Dup2(pRicezioneFd[1], 2);
// closePipe(pipeFd[0]);
// closePipe(pRicezioneFd[1]);
if(execl("/usr/bin/bc", "bc", "-lq", NULL) == -1)
{
perror("programma non reperibile");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
void closePipe(int pipeFd)
{
if(close(pipeFd) == -1)
{
perror("impossibile chiudere il fd della pipe");
exit(EXIT_FAILURE);
}
}
void Dup2(int pipeTempFd, int fd)
{
if(dup2(pipeTempFd, fd) == -1)
{
perror("Impossibile eseguire la dup2");
exit(EXIT_FAILURE);
}
}
void Write(int pipeTempFd, char stringa[], int n)
{
if(write(pipeTempFd, stringa, n) == -1)
{
perror("impossibile scrivere sulla pipa");
exit(EXIT_FAILURE);
}
}
void Read(int pipeTempFd, char stringa[], int n)
{
if(read(pipeTempFd, stringa, n) == -1)
{
perror("impossibile leggere dalla pipe pipa");
exit(EXIT_FAILURE);
}
}
我认为我的代码与您的相似,一个主要变化是 exec 调用的参数。另一个变化是我在子进程中只有 2 个 dup2 调用,一个用于更改标准输入,另一个用于更改标准输出。你只需要改变这些。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define READ_END 0
#define WRITE_END 1
int main()
{
char *input = NULL;
size_t len = 0;
ssize_t amt_read = 0;
puts("Please enter a string: ");
amt_read = getline(&input, &len, stdin);
if(amt_read < 0)
exit(EXIT_FAILURE);
pid_t pid;
int fd[2];
int fd_return[2];
// Create the pipes
pipe(fd);
pipe(fd_return);
pid = fork();
if(pid==0)
{ // If child process
dup2(fd[READ_END], STDIN_FILENO);
dup2(fd_return[WRITE_END], STDOUT_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
close(fd_return[WRITE_END]);
close(fd_return[READ_END]);
execl("/usr/bin/bc", "/usr/bin/bc", "-lq", (char *)NULL);
fprintf(stderr, "Failed to execute\n");
exit(EXIT_FAILURE);
}
else
{ // If parent process
int status;
close(fd[READ_END]);
close(fd_return[WRITE_END]);
// Write to the pipe
write(fd[WRITE_END], input, strlen(input));
close(fd[WRITE_END]);
// Wait for the child to finish
waitpid(pid, &status, 0);
char buff[N];
buff[N-1] = 0;
read(fd_return[READ_END], buff, N-1);
*(index(buff, '\n')) = '[=10=]'; // Add null terminator on your own
close(fd_return[READ_END]);
printf("The Result is: %s\n", buff);
}
free(input);
return 0;
}
编辑:
我编辑了代码并调试了它。我还更改了用户输入原理图,所以现在您不再为用户输入分配静态存储空间,而是动态分配,然后在最后使用 free();
释放该存储空间
请注意,我确实留下了用于读取输入的静态存储,如果需要,您可以在以后更改它。
非法字符:^@是因为write()写的太多了,注意现在只写了strlen(buff)的数量
注意:除非字符串以“...\n[=23=]”结尾,否则 bc 的输入将不起作用,幸运的是 getline() 默认情况下会这样做。
另外,我让所有的管道都关闭了,这不是导致问题的原因。
您正在将大部分未初始化的 stringa 的所有 1024 个字节写入 bc
,然后它会因非法字符而窒息。 bc
期望换行符终止,“纯文本”表达式。
#define N 1024
char stringa[N]; // stringa := "6[=10=][=10=]17>[=10=][=10=]041..."
scanf("%s", stringa); // stringa := "1+2[=10=]7>[=10=][=10=]041..."
// ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1], stringa, N); // ohimè!
你会想要这样的东西,而不是:
Write(pipeFd[1], stringa, strlen(stringa));
Write(pipeFd[1], "\n", 1);
我必须在 c 中使用管道模拟此命令: echo "
代码是这样的,但是我不明白为什么它不起作用;特别是,“bc”命令似乎无法从标准输入中读取表达式。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define LEGGI(stringa) if(scanf("%s", stringa) == 0) \
{ \
perror("Impossibile leggere la stringa"); \
exit(EXIT_FAILURE); \
} \
void closePipe(int pipeFd);
void Dup2(int pipeTempFd, int fd);
void Write(int pipeTempFd, char stringa[], int n);
void Read(int pipeTempFd, char stringa[], int n);
int main()
{
char stringa[N];
LEGGI(stringa);
int pipeFd[2];
int pRicezioneFd[2];
if(pipe(pipeFd) == -1 || pipe(pRicezioneFd) == -1)
{
perror("impossibile eseguire la pipe");
exit(EXIT_FAILURE);
}
if(strncmp(stringa, "exit", N) != 0)
{
pid_t processPid;
if((processPid = fork()) == 1)
{
perror("impossibile eseguire la fork");
exit(EXIT_FAILURE);
}
if(processPid != 0)
{
closePipe(pipeFd[0]);
closePipe(pRicezioneFd[1]);
printf("operazione: %s\n", stringa);
Write(pipeFd[1], stringa, N);
closePipe(pipeFd[1]);
read(pRicezioneFd[0], stringa, N);
closePipe(pRicezioneFd[0]);
if(wait(NULL) == -1)
{
perror("Impossibile eseguire la wait");
exit(EXIT_FAILURE);
}
printf("%s\n", stringa);
}
else
{
closePipe(pipeFd[1]);
closePipe(pRicezioneFd[0]);
Dup2(pipeFd[0], 0);
Dup2(pRicezioneFd[1], 1);
Dup2(pRicezioneFd[1], 2);
// closePipe(pipeFd[0]);
// closePipe(pRicezioneFd[1]);
if(execl("/usr/bin/bc", "bc", "-lq", NULL) == -1)
{
perror("programma non reperibile");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
void closePipe(int pipeFd)
{
if(close(pipeFd) == -1)
{
perror("impossibile chiudere il fd della pipe");
exit(EXIT_FAILURE);
}
}
void Dup2(int pipeTempFd, int fd)
{
if(dup2(pipeTempFd, fd) == -1)
{
perror("Impossibile eseguire la dup2");
exit(EXIT_FAILURE);
}
}
void Write(int pipeTempFd, char stringa[], int n)
{
if(write(pipeTempFd, stringa, n) == -1)
{
perror("impossibile scrivere sulla pipa");
exit(EXIT_FAILURE);
}
}
void Read(int pipeTempFd, char stringa[], int n)
{
if(read(pipeTempFd, stringa, n) == -1)
{
perror("impossibile leggere dalla pipe pipa");
exit(EXIT_FAILURE);
}
}
我认为我的代码与您的相似,一个主要变化是 exec 调用的参数。另一个变化是我在子进程中只有 2 个 dup2 调用,一个用于更改标准输入,另一个用于更改标准输出。你只需要改变这些。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define READ_END 0
#define WRITE_END 1
int main()
{
char *input = NULL;
size_t len = 0;
ssize_t amt_read = 0;
puts("Please enter a string: ");
amt_read = getline(&input, &len, stdin);
if(amt_read < 0)
exit(EXIT_FAILURE);
pid_t pid;
int fd[2];
int fd_return[2];
// Create the pipes
pipe(fd);
pipe(fd_return);
pid = fork();
if(pid==0)
{ // If child process
dup2(fd[READ_END], STDIN_FILENO);
dup2(fd_return[WRITE_END], STDOUT_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
close(fd_return[WRITE_END]);
close(fd_return[READ_END]);
execl("/usr/bin/bc", "/usr/bin/bc", "-lq", (char *)NULL);
fprintf(stderr, "Failed to execute\n");
exit(EXIT_FAILURE);
}
else
{ // If parent process
int status;
close(fd[READ_END]);
close(fd_return[WRITE_END]);
// Write to the pipe
write(fd[WRITE_END], input, strlen(input));
close(fd[WRITE_END]);
// Wait for the child to finish
waitpid(pid, &status, 0);
char buff[N];
buff[N-1] = 0;
read(fd_return[READ_END], buff, N-1);
*(index(buff, '\n')) = '[=10=]'; // Add null terminator on your own
close(fd_return[READ_END]);
printf("The Result is: %s\n", buff);
}
free(input);
return 0;
}
编辑: 我编辑了代码并调试了它。我还更改了用户输入原理图,所以现在您不再为用户输入分配静态存储空间,而是动态分配,然后在最后使用 free();
释放该存储空间请注意,我确实留下了用于读取输入的静态存储,如果需要,您可以在以后更改它。
非法字符:^@是因为write()写的太多了,注意现在只写了strlen(buff)的数量
注意:除非字符串以“...\n[=23=]”结尾,否则 bc 的输入将不起作用,幸运的是 getline() 默认情况下会这样做。
另外,我让所有的管道都关闭了,这不是导致问题的原因。
您正在将大部分未初始化的 stringa 的所有 1024 个字节写入 bc
,然后它会因非法字符而窒息。 bc
期望换行符终止,“纯文本”表达式。
#define N 1024
char stringa[N]; // stringa := "6[=10=][=10=]17>[=10=][=10=]041..."
scanf("%s", stringa); // stringa := "1+2[=10=]7>[=10=][=10=]041..."
// ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1], stringa, N); // ohimè!
你会想要这样的东西,而不是:
Write(pipeFd[1], stringa, strlen(stringa));
Write(pipeFd[1], "\n", 1);