在 c.But 中实现管道不起作用
Implementing pipe in c.But it is not working
我正在尝试使用 C 语言实现管道。
我正在通过创建子进程
为由管道分隔的每个命令执行循环
以下是我的代码:
int main(int argc, char **argv)
{
char *cmd,*splitcmd;
int i,j,nargc=0,characters;
char **cmdArray;
size_t bufsize = 1024;
int *pipefd;
int pipeArrCount;
pid_t pid,wpid;
int status = 0;
int savestdoutfd = dup(fileno(stdout));
int savestdinfd = dup(fileno(stdin));
cmd = (char *)malloc(bufsize * sizeof(char));
characters = getline(&cmd,&bufsize,stdin);
// printf("%s%d",cmd,characters);
if(cmd[characters-1]=='\n')
{
// printf("in c");
cmd[characters-1]='[=11=]';
characters--;
}
cmdArray = (char**)malloc(sizeof(char *) * 100);
splitcmd=strtok(cmd,"|");
// printf("%s\n",cmd);
while((splitcmd))
{
cmdArray[nargc] = splitcmd;
if(cmdArray[nargc][(strlen(cmdArray[nargc]))-1]==' ')
cmdArray[nargc][(strlen(cmdArray[nargc]))-1]='[=11=]';
printf("%d %s",nargc,cmdArray[nargc]);
nargc++;
splitcmd = strtok(NULL,"|");
}
pipefd=(int*)malloc(2*nargc*sizeof(int));
printf("%d\n",nargc);
pipeArrCount=2*(nargc-1);
printf("%d\n",pipeArrCount);
//exit(0);
for(i=0;i<pipeArrCount;i)
{
printf("making pipe for process %d\n",i);
pipe(pipefd+i);
i=i+2;
}
//exit(0);
for(i=0;i<nargc;i)
{
printf("parent count %d\n",i);
if(i==0)
{
printf("Creating child %d\n",i);
// As it is first process we need to make write end of the pipe as stdout.
if ((pid=fork()) == 0)
{
printf("Creating first child %d for command %s\n",i,cmdArray[i]);
printf("EXECUTING FIRST PROCESS\n");
printf("Writing in pipe[%d]\n",2*i+1);
//close(pipefd[0]);
dup2(pipefd[2*i+1],fileno(stdout));
//closing all other pipes
for(j=0;j<(2*nargc);j++)
{
//if(j!=2*i+1)
close(pipefd[j]);
}
system(cmdArray[i]);
//dup2(savestdoutfd,fileno(stdout));
printf("Stdout is again restored\n");
//printf("pipe [%d] contains %d ",2*i+1,pipefd[2*i+1]);
exit(0);
}
}
else if(i!=nargc-1)
{
if (fork() == 0)
{
printf("EXECUTING MIDDLE PROCESS\n");
printf("Command to execute %s \n",cmdArray[i]);
printf("Reading from pipe[%d]\n",(2*(i-1)));
printf("writing on pipe[%d]\n",(2*i)+1);
dup2(pipefd[(2*(i-1))], 0); //Read end of the previous process pipe as stdin
dup2(pipefd[(2*i)+1], 1); //Write end of the pipe of current process as stdout
//closing all other pipes
for(j=0;j<(2*nargc);j++)
{
//if((j!=(2*(i-1))) && (j!=(2*i)+1))
close(pipefd[j]);
}
system(cmdArray[i]);
exit(0);
}
}
else
{
if (fork() == 0)
{
printf("Creating last child %d for command %s\n",i,cmdArray[i]);
printf("Reading from pipe[%d]\n",(2*(i-1)));
//close(pipefd[1]);
dup2(pipefd[(2*(i-1))],fileno(stdin)); //Read from the end of the previous process pipe as stdin
//printf("EXECUTING LAST PROCESS\n");
//closing all other pipes
for(i=0;j<(2*nargc);j++)
{
//if(j!=(2*(i-1)))
close(pipefd[j]);
}
dup2(savestdoutfd,fileno(stdout));
close(savestdoutfd);
system(cmdArray[i]);
dup2(savestdinfd,fileno(stdin));
close(savestdinfd);
exit(0);
}
}
i=i+1;
sleep(1);
}
while ((wpid = wait(&status)) > 0);
}
没有得到第二个命令的任何输出
现在我正在尝试执行这种 'A | B ' 类型的命令
如果执行代码
,命令和管道之间的space是必要的
我执行了你的代码。它适用于单个管道,例如:
ls | grep "a" and ls | wc.
它不适用于双管道,如:ls | grep "a" | wc
。
错误是 错误的文件描述符 。
我没有调试这个错误,似乎 "else if" 子句中的文件描述符处理不当。不管怎样,你的问题是它不适用于像 A | B
这样的单管道。但确实如此。
希望对您有所帮助。
您离正确的解决方案不远了。但首先是一些通用的评论:
- 您的代码未显示任何包含:请添加它们
- 您正在从 malloc 转换 return 值。这在 C++ 中是必需的,但在 C 中不是:你应该写
cmd = malloc(bufsize * sizeof(char));
- 您可以编写循环
for(i=0;i<pipeArrCount;i+=2)
删除 i=i+2
因为它在 C 中更常见,或者至少 for(i=0;i<pipeArrCount;)
以避免警告。
现在是您问题的真正原因。您为管道分配了一个大小为 2*nargc
的数组,但只初始化了 2*(nargc-1)
。最后 2 个没有初始化,这应该是无害的,但是你关闭了整个数组(for(j=0;j<(2*nargc);j++)
。在我的测试中,它们是 0(可能是因为调试模式)所以你正在为你的孩子关闭标准输入。只需使用:
for(j=0;j<pipeArrCount;j++)
{
close(pipefd[j]);
}
这还不是全部。你在最后一个命令中也有错字,你用 i
而不是 j
写了 for(i=0;j<(2*nargc);j++)
。正如 Kulwant Singh 所指出的那样,它没有关闭任何允许代码 运行 仅使用 2 个命令的内容。
并且您还必须关闭 parent 进程中的管道。程序的结尾应该是:
//closing all pipes
for (j=0; j<pipeArrCount; j++) {
close(pipefd[j]);
}
while ((wpid = wait(&status)) > 0);
}
我正在尝试使用 C 语言实现管道。 我正在通过创建子进程
为由管道分隔的每个命令执行循环以下是我的代码:
int main(int argc, char **argv)
{
char *cmd,*splitcmd;
int i,j,nargc=0,characters;
char **cmdArray;
size_t bufsize = 1024;
int *pipefd;
int pipeArrCount;
pid_t pid,wpid;
int status = 0;
int savestdoutfd = dup(fileno(stdout));
int savestdinfd = dup(fileno(stdin));
cmd = (char *)malloc(bufsize * sizeof(char));
characters = getline(&cmd,&bufsize,stdin);
// printf("%s%d",cmd,characters);
if(cmd[characters-1]=='\n')
{
// printf("in c");
cmd[characters-1]='[=11=]';
characters--;
}
cmdArray = (char**)malloc(sizeof(char *) * 100);
splitcmd=strtok(cmd,"|");
// printf("%s\n",cmd);
while((splitcmd))
{
cmdArray[nargc] = splitcmd;
if(cmdArray[nargc][(strlen(cmdArray[nargc]))-1]==' ')
cmdArray[nargc][(strlen(cmdArray[nargc]))-1]='[=11=]';
printf("%d %s",nargc,cmdArray[nargc]);
nargc++;
splitcmd = strtok(NULL,"|");
}
pipefd=(int*)malloc(2*nargc*sizeof(int));
printf("%d\n",nargc);
pipeArrCount=2*(nargc-1);
printf("%d\n",pipeArrCount);
//exit(0);
for(i=0;i<pipeArrCount;i)
{
printf("making pipe for process %d\n",i);
pipe(pipefd+i);
i=i+2;
}
//exit(0);
for(i=0;i<nargc;i)
{
printf("parent count %d\n",i);
if(i==0)
{
printf("Creating child %d\n",i);
// As it is first process we need to make write end of the pipe as stdout.
if ((pid=fork()) == 0)
{
printf("Creating first child %d for command %s\n",i,cmdArray[i]);
printf("EXECUTING FIRST PROCESS\n");
printf("Writing in pipe[%d]\n",2*i+1);
//close(pipefd[0]);
dup2(pipefd[2*i+1],fileno(stdout));
//closing all other pipes
for(j=0;j<(2*nargc);j++)
{
//if(j!=2*i+1)
close(pipefd[j]);
}
system(cmdArray[i]);
//dup2(savestdoutfd,fileno(stdout));
printf("Stdout is again restored\n");
//printf("pipe [%d] contains %d ",2*i+1,pipefd[2*i+1]);
exit(0);
}
}
else if(i!=nargc-1)
{
if (fork() == 0)
{
printf("EXECUTING MIDDLE PROCESS\n");
printf("Command to execute %s \n",cmdArray[i]);
printf("Reading from pipe[%d]\n",(2*(i-1)));
printf("writing on pipe[%d]\n",(2*i)+1);
dup2(pipefd[(2*(i-1))], 0); //Read end of the previous process pipe as stdin
dup2(pipefd[(2*i)+1], 1); //Write end of the pipe of current process as stdout
//closing all other pipes
for(j=0;j<(2*nargc);j++)
{
//if((j!=(2*(i-1))) && (j!=(2*i)+1))
close(pipefd[j]);
}
system(cmdArray[i]);
exit(0);
}
}
else
{
if (fork() == 0)
{
printf("Creating last child %d for command %s\n",i,cmdArray[i]);
printf("Reading from pipe[%d]\n",(2*(i-1)));
//close(pipefd[1]);
dup2(pipefd[(2*(i-1))],fileno(stdin)); //Read from the end of the previous process pipe as stdin
//printf("EXECUTING LAST PROCESS\n");
//closing all other pipes
for(i=0;j<(2*nargc);j++)
{
//if(j!=(2*(i-1)))
close(pipefd[j]);
}
dup2(savestdoutfd,fileno(stdout));
close(savestdoutfd);
system(cmdArray[i]);
dup2(savestdinfd,fileno(stdin));
close(savestdinfd);
exit(0);
}
}
i=i+1;
sleep(1);
}
while ((wpid = wait(&status)) > 0);
}
没有得到第二个命令的任何输出 现在我正在尝试执行这种 'A | B ' 类型的命令 如果执行代码
,命令和管道之间的space是必要的我执行了你的代码。它适用于单个管道,例如:
ls | grep "a" and ls | wc.
它不适用于双管道,如:ls | grep "a" | wc
。
错误是 错误的文件描述符 。
我没有调试这个错误,似乎 "else if" 子句中的文件描述符处理不当。不管怎样,你的问题是它不适用于像 A | B
这样的单管道。但确实如此。
希望对您有所帮助。
您离正确的解决方案不远了。但首先是一些通用的评论:
- 您的代码未显示任何包含:请添加它们
- 您正在从 malloc 转换 return 值。这在 C++ 中是必需的,但在 C 中不是:你应该写
cmd = malloc(bufsize * sizeof(char));
- 您可以编写循环
for(i=0;i<pipeArrCount;i+=2)
删除i=i+2
因为它在 C 中更常见,或者至少for(i=0;i<pipeArrCount;)
以避免警告。
现在是您问题的真正原因。您为管道分配了一个大小为 2*nargc
的数组,但只初始化了 2*(nargc-1)
。最后 2 个没有初始化,这应该是无害的,但是你关闭了整个数组(for(j=0;j<(2*nargc);j++)
。在我的测试中,它们是 0(可能是因为调试模式)所以你正在为你的孩子关闭标准输入。只需使用:
for(j=0;j<pipeArrCount;j++)
{
close(pipefd[j]);
}
这还不是全部。你在最后一个命令中也有错字,你用 i
而不是 j
写了 for(i=0;j<(2*nargc);j++)
。正如 Kulwant Singh 所指出的那样,它没有关闭任何允许代码 运行 仅使用 2 个命令的内容。
并且您还必须关闭 parent 进程中的管道。程序的结尾应该是:
//closing all pipes
for (j=0; j<pipeArrCount; j++) {
close(pipefd[j]);
}
while ((wpid = wait(&status)) > 0);
}