在C中写字符到管道

时间:2013-04-20 14:59:57

标签: c char signals fork pipe

我有以下程序,基本上是从键盘读取字符(getch()这样做而不需要点击'ENTER',函数取自这里:Capture characters from standard input without waiting for enter to be pressed) ,如果char是合法移动之一(LEFT,RIGHT等),则将其写入管道,draw.out正在读取。

draw.out正在读取收到的输入并打印到屏幕。 (假设这个程序工作正常,我保证问题仅在以下代码中。)

问题在于:

  1. draw.out表现得像是一遍又一遍地接受我的输入。这意味着,出于某种原因,即使我按下DOWN键只执行一次,它也会发送draw.out,好像我多次点击它一样。

  2. 发送一个输入后,我再也无法发送了,好像循环正在停止。

  3. 试图打破我的头几个小时...我真的很感激帮助。

    int main(int argc, const char* argv[])
    {
    pid_t child_pid;
    int fda[2];
    if(pipe(fda)<0)
        perror("pipe error");
    
    if((child_pid=fork())<0)
        perror("fork error");
    else
    {
        //if we're in father
        if(child_pid>0)
        {
            char c=' ';
    
            //close read side
            close(fda[0]);
    
            while(c!=QUIT)
            {
                //get an instruction from keyboard
                while(c!=ROTATE && c!=LEFT && c!=RIGHT &&
                        c!=DOWN && c!=QUIT)
                {
                    c=getch();
                }
    
                //write the instruction to pipe
                write(fda[1],&c,1);
                //notify the child
                kill(child_pid,SIGUSR2);
    
            }
        }
        //if we're in child process
        else
        {
            dup2(fda[0],0);
            close(fda[0]);
            close(fda[1]);
            execl("./draw.out","./draw.out",NULL);
        }
    }
    
    //close everything
    close(fda[0]);
    close(fda[1]);
    return 0;
    }
    
    //this function works well in linux with tsch installed or in SSH bash shell
    char getch()
    {
    char buf = 0;
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
            perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
            perror("tcsetattr ICANON");
    if (read(0, &buf, 1) < 0)
            perror ("read()");
    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    if (tcsetattr(0, TCSADRAIN, &old) < 0)
            perror ("tcsetattr ~ICANON");
    return (buf);
    }
    

2 个答案:

答案 0 :(得分:1)

发送信息c后,您需要将其设置为ROTATELEFTRIGHTDOWN以外的值。

如果你不getch()将永远不会再被召唤......

所以在外部while的末尾(在kill之后)或在循环开始时(恰好在包含while调用的getch()之前)添加

之类的东西
if (c != QUIT)
  c = ' ';

答案 1 :(得分:1)

将while循环更改为do / while循环,以确保始终至少调用getch()一次。

do
{
    c = getch();
}
while (c != ROTATE && c != LEFT && c != RIGHT && c != DOWN && c != QUIT);