首页 > 系统服务 > 详细

Understanding Unix/Linux Programming-用户程序:play_again3

时间:2016-03-18 15:59:11      阅读:445      评论:0      收藏:0      [点我收藏+]
  1 /* play_again3.c
  2  * purpuse: ask if user wants another play 
  3  * better : instant response without echo
  4               set tty into no-delay mode
  5               read char , return result
  6               reset terminal mode on Internet
  7  * returns: 0 -> yes , 1 -> no 
  8  */
  9  
 10  #include <stdio.h>
 11  #include <stdlib.h>
 12  #include <fcntl.h>
 13  #include <termios.h>
 14  #include <string.h>
 15  
 16  #define ASK "Do you want another play?"
 17  #define TRIES 3
 18  #define SLEEPTIME 2
 19  #define BEEP putchar(‘\a‘);
 20 
 21 
 22  int get_response(char *);
 23  int get_ok_char(void);
 24  void set_nodelay_mode(void);
 25  void set_cr_noecho_mode(void);
 26  void tty_mode(int); 
 27  
 28  int main()
 29  {
 30      int response ;
 31      tty_mode(0);   // save tty mode
 32      set_cr_noecho_mode();
 33      set_nodelay_mode();
 34      response = get_response(ASK);
 35      tty_mode(1);   // restore tty mode
 36      return response ;
 37  }
 38  
 39  int get_response(char * qiz)
 40  {
 41      int input ;
 42      int maxtries = TRIES ;
 43      printf("%s(y/n)" , qiz);
 44      fflush(stdout);
 45      while(1)
 46      {
 47         BEEP ;
 48         sleep(SLEEPTIME);
 49         input = tolower(get_ok_char()) ;
 50         if(input == y)
 51         {
 52             printf("\n");
 53             return 0 ;
 54         }
 55         if(input == n)
 56         {
 57             printf("\n");
 58             return 1 ;
 59         }
 60         if(maxtries -- <= 0 )
 61         {
 62             printf("\n");
 63             return 2 ;
 64         }
 65         BEEP ;
 66      }
 67  }
 68  
 69 int get_ok_char(void)
 70 {
 71     int c ;
 72     while( (c = getchar() ) != EOF && strchr("yYnN" , c ) == NULL )
 73         ;
 74     return c ;
 75 }
 76 
 77 void set_cr_noecho_mode(void)
 78 {
 79     struct  termios ttystate ;
 80     tcgetattr(0 , &ttystate);
 81     ttystate.c_lflag &= ~ICANON ;   // No Buffering
 82     ttystate.c_lflag &= ~ECHO ;
 83     ttystate.c_cc[VMIN] = 1 ;   //Get one char one time 
 84     tcsetattr( 0 , TCSANOW , &ttystate);    
 85 }
 86 
 87 void set_nodelay_mode(void)
 88 {
 89     int termflags ;
 90     termflags = fcntl(0 , F_GETFL);
 91     termflags |= O_NDELAY ;
 92     fcntl(0 , F_SETFL , termflags) ;
 93 }
 94 
 95 void tty_mode(int mode)
 96 {
 97     static struct termios original_mode ;// 设置静态结构体变量
 98     if(mode == 0 )
 99     {
100         tcgetattr( 0 , & original_mode);// 存储原有设置
101     }
102     else
103     {
104         //还原原有设置
105         if( tcsetattr(0 , TCSANOW , & original_mode) == -1 )
106         {
107             perror("Restore tty settings failed!\n");
108         }
109     }
110 }

 这里使用到了非阻塞输入

  怎么解释非阻塞输入与阻塞输入?

  书上解释:

    当调用getchar或者read从文件描述符读取输入时,这些调用通常会等待输入,这叫做阻塞输入(block input)。在play_again的例子中,对于getchar的调用使得程序一直等待用户的输入,知道用户输入一个字符。程序被阻塞,知道能够获得某些字符或是检测到文件的末尾。那么如何关闭输入阻塞呢?

    阻塞不仅仅是终端连接的属性,而是任何一个打开的文件的属性。(也就是说阻塞实际上是文件的属性咯,不论是磁盘文件还是设备文件)。毕竟程序或者进程是与文件通过文件描述符连接的。

    程序可以通过fcntl或者open为文件描述符启动非阻塞输入(nonblock input)。play_again3使用fcntl为文件描述符开启O_NDELAY标志。

    关闭一个文件描述符的阻塞状态并且调用read结果会如何呢?如果能够获得输入,read会获得输入并且返回所获得的字数。如果没有输入字符,read返回0,这就像遇到文件末尾一样,如果有错误,read返回1。

    非阻塞操作内部实现非常简单。每个文件都有一块保存未读取数据的地方。如果文件描述符置位O_NDELAY,并且那块空间是空的,则read调用返回0。

    阅读O_NDELAY相关的Linux源代码,就可以了解实现细节。(准备以后再阅读源码吧

Understanding Unix/Linux Programming-用户程序:play_again3

原文:http://www.cnblogs.com/NJdonghao/p/5292319.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!