迷失在多个 Fork()、Pipe() 和 Select() 中
希望我能在这里找到一些帮助,因为我开始放弃。请注意,这是一项家庭作业,因此它可能很愚蠢。
语境: 必须编写一些将由 shell 执行的东西,如下所示:
logn [--tick n] cmd [args] [, cmd [args]]...
基本上,它是一个同时运行多个程序的程序。
限制条件: 每个输出行必须以它的命令号开头,格式为 printf "%d: %s" IE: 0:第一个命令的第一行。
0:第一个命令的第二行。
1:第二个命令的第一行。
0:第一个命令的第三行。
1:第二条命令的第二行。
如果指定了刻度,如果 n 秒内没有发送任何输出,系统将打印一个句点。
必须使用 Select()
如果最后输出是句点,系统不会打印另一个句点。
现在这是我的问题!我可以用一个命令让它工作。当我尝试使其成为多个命令时,我似乎失败了。我相信这可能是我的方法。也许你们中的一些人能够帮助我。
这是我尝试使用 Multiple Cmd 的方法。我可能完全错了,因此我需要帮助:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include "readline.h"
// Reference: http://www.gnu.org/s/libc/manual/html_node/Waiting-for-I_002fO.html
int input_timeout (int filedes, unsigned int seconds)
{
fd_set set;
struct timeval timeout;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
/* select returns 0 if timeout, 1 if input available, -1 if error. */
return (select (FD_SETSIZE,&set, NULL, NULL, &timeout));
}
/* Fetches the number of commands in parameters. Number of Commas + 1 */
int getNbCmd(char ** argv)
{
int nbCmd = 1;
int i;
while(argv[i] != '\0')
{
if(strcmp(argv[i], ",") == 0)
nbCmd++;
i++;
}
return nbCmd;
}
/* Fills the Command Array */
void getCommandes(char *** tbCmd, int argc, char ** argv)
{
int indexArgv = 1;
int indexCmd = 0;
int indexTbCmd = 0;
char ** cmd = (char **)malloc(argc*sizeof(char *));
if(strcmp(argv[indexArgv], "--tick") == 0)
indexArgv = 3;
while (indexArgv < argc)
{
if(strcmp(argv[indexArgv], ",") == 0)
{
cmd[indexCmd] = (char *) 0;
tbCmd[indexTbCmd] = cmd;
free(cmd);
cmd = (char **)malloc(argc*sizeof(char *));
indexTbCmd++;
indexCmd = 0;
}
else
{
char * arg;
arg = argv[indexArgv];
cmd[indexCmd] = arg;
indexCmd++;
}
indexArgv++;
}
cmd[indexCmd] = (char *) 0;
tbCmd[indexTbCmd] = cmd;
free(cmd);
}
int main (int argc, char ** argv)
{
int nbCmds = getNbCmd(argv);
int tick = -1;
char *** tbCmd = (char ***) malloc (nbCmds*sizeof(char **));
if(strcmp(argv[1], "--tick") == 0)
tick = atoi(argv[2]);
getCommandes(tbCmd, argc, argv);
int i;
pid_t pidM[nbCmds];
int p[nbCmds][2];
for (i = 0;i < nbCmds;i++)
{
if ( pipe( p[i] ) != 0 ){ perror( "pipe()" ); exit(1); }
// fork() to get child process
pidM[i] = fork();
if ( pidM[i] < 0 ){ perror( "fork()" ); exit(1); }
else if (pidM[i] == 0)
{
close(p[i][0]);
dup2(p[i][1], STDOUT_FILENO);
int ret;
ret = execvp(tbCmd[i][0], tbCmd[i]);
}
else
{
close(p[i][1]);
char * buffer;
int retval = 1;
int pntAfficher = 0; //Boolean for Period Printing
/* select returns 0 if timeout, 1 if input available, -1 if error. */
if(tick >= 0)
retval = input_timeout(p[i][0], tick);
if (retval == 0 && pntAfficher == 0)
{
printf(".\n");
pntAfficher = 1;
}
buffer = readline(p[i][0]);
while(buffer[0] != '\0')
{
printf("%d: %s",i, buffer);
free(buffer);
/* select returns 0 if timeout, 1 if input available, -1 if error. */
if(tick >= 0)
retval = input_timeout(p[i][0], tick);
if (retval == 0 && pntAfficher == 0)
{
printf(".\n");
pntAfficher = 1;
}
buffer = readline(p[i][0]);
pntAfficher = 0;
free(buffer);
}
}
}
free(tbCmd);
}
Hope I can find some help here cause I'm starting to give up. Heads up as this is an homework assignment, hence why it might be stupid.
Context:
Have to program something which will be shell executed as such:
logn [--tick n] cmd [args] [, cmd [args]]...
Basically, it's a program that multiple programs simultanously.
Constraints:
Each output line has to start with it's command number in front in format printf "%d: %s"
ie:
0: first line of first command.
0: second line of first command.
1: first line of second command.
0: third line of first command.
1: second line of second command.
If the tick has been specified, system will print a period if no output has been sent for n seconds.
Must use Select()
If the last output was a period, system does not print another period.
Now here is my issue! I was able to make it work with a single command. The moment I try to make it multiple command, I seem to fail. I believe it may be my approach. Maybe some of you would be able to help me.
Here is what I attempted for Multiple Cmd. It may possbile that I am totally wrong, hence why I need help:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include "readline.h"
// Reference: http://www.gnu.org/s/libc/manual/html_node/Waiting-for-I_002fO.html
int input_timeout (int filedes, unsigned int seconds)
{
fd_set set;
struct timeval timeout;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
/* select returns 0 if timeout, 1 if input available, -1 if error. */
return (select (FD_SETSIZE,&set, NULL, NULL, &timeout));
}
/* Fetches the number of commands in parameters. Number of Commas + 1 */
int getNbCmd(char ** argv)
{
int nbCmd = 1;
int i;
while(argv[i] != '\0')
{
if(strcmp(argv[i], ",") == 0)
nbCmd++;
i++;
}
return nbCmd;
}
/* Fills the Command Array */
void getCommandes(char *** tbCmd, int argc, char ** argv)
{
int indexArgv = 1;
int indexCmd = 0;
int indexTbCmd = 0;
char ** cmd = (char **)malloc(argc*sizeof(char *));
if(strcmp(argv[indexArgv], "--tick") == 0)
indexArgv = 3;
while (indexArgv < argc)
{
if(strcmp(argv[indexArgv], ",") == 0)
{
cmd[indexCmd] = (char *) 0;
tbCmd[indexTbCmd] = cmd;
free(cmd);
cmd = (char **)malloc(argc*sizeof(char *));
indexTbCmd++;
indexCmd = 0;
}
else
{
char * arg;
arg = argv[indexArgv];
cmd[indexCmd] = arg;
indexCmd++;
}
indexArgv++;
}
cmd[indexCmd] = (char *) 0;
tbCmd[indexTbCmd] = cmd;
free(cmd);
}
int main (int argc, char ** argv)
{
int nbCmds = getNbCmd(argv);
int tick = -1;
char *** tbCmd = (char ***) malloc (nbCmds*sizeof(char **));
if(strcmp(argv[1], "--tick") == 0)
tick = atoi(argv[2]);
getCommandes(tbCmd, argc, argv);
int i;
pid_t pidM[nbCmds];
int p[nbCmds][2];
for (i = 0;i < nbCmds;i++)
{
if ( pipe( p[i] ) != 0 ){ perror( "pipe()" ); exit(1); }
// fork() to get child process
pidM[i] = fork();
if ( pidM[i] < 0 ){ perror( "fork()" ); exit(1); }
else if (pidM[i] == 0)
{
close(p[i][0]);
dup2(p[i][1], STDOUT_FILENO);
int ret;
ret = execvp(tbCmd[i][0], tbCmd[i]);
}
else
{
close(p[i][1]);
char * buffer;
int retval = 1;
int pntAfficher = 0; //Boolean for Period Printing
/* select returns 0 if timeout, 1 if input available, -1 if error. */
if(tick >= 0)
retval = input_timeout(p[i][0], tick);
if (retval == 0 && pntAfficher == 0)
{
printf(".\n");
pntAfficher = 1;
}
buffer = readline(p[i][0]);
while(buffer[0] != '\0')
{
printf("%d: %s",i, buffer);
free(buffer);
/* select returns 0 if timeout, 1 if input available, -1 if error. */
if(tick >= 0)
retval = input_timeout(p[i][0], tick);
if (retval == 0 && pntAfficher == 0)
{
printf(".\n");
pntAfficher = 1;
}
buffer = readline(p[i][0]);
pntAfficher = 0;
free(buffer);
}
}
}
free(tbCmd);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要在一个循环中分叉所有子级,然后在第二个循环中,从所有子级中读取所有数据。
您希望并行侦听所有子级的输出(这就是
select
为您所做的事情),但所有子级都需要运行才能正常工作。您当前的for
循环生成一个子循环,然后转到select
... 这不是它的正确位置。You need to fork all the children in a loop, then in a second loop, read all the data out from all the children.
You're wanting to listen to the output of all the children in parallel (which is what the
select
is doing for you), but all the children need to be running for that to work. Your currentfor
loop spawns a child, then goes to theselect
... which isn't the right place for it.不太清楚当你说“似乎失败”时你的意思,但看起来你需要修改你的代码才能倾听你所有孩子的声音。 select 可以这样做,看 select 的 man ,尝试使用 FD_SET 添加多个 FD
Not quite sure what you mean when you say "seem to fail" but it looks like you need to modify your code in order to listen to ALL your children. select can be used to do so, just look at the man of select and try to add multiple FDs using FD_SET