对终端的读写进行设置(2)
admin
2024-02-01 10:48:39

2.与终端进行对话



Linux是多用户系统,终端会有很多个。但是/dev/tty始终指向当前终端


3.终端驱动程序和通用终端接口



    1.控制终端的主要功能如下:



    (1)行编辑:是否允许使用退格键编辑。
    (2)缓存:是立即读取字符,还是等待一段可配置的延迟之后再读取它们
    (3)回显:允许控制字符的回显:例如读取密码
    (4)换行/回车:CR/LF:定义如何再输入输出时映射回车/换行符。比如打印\n字符时应该如何处理。
    (5)线速:这一个功能很少用在PC控制台,但是对调制解调器或者通过串行线连接的终端就很重要



    2.termios结构体



        这个结构体可以影响终端的几种模式
        (1).输入模式
        (2).输出模式
        (3).控制模式
        (4).本地模式
        (5).特殊控制模式
    struct termios{
        tcflag_t c_iflag;
        tcflag_t c_oflag;
        tcflag_t c_cflag;
        tcflag_t c_lflag
        cc_t c_cc[NCCS]
    };
    这个结构体的成员控制这上面的几种模式,一一对应


    3.功能


 (1),获取终端的属性


    int tcgetattr(int fd, struct termios* termios_p)
    这个函数会把对应的终端属性写入到termios_p指向的结构体中
    


 

    (2).配置终端的属性



    int tcsetattr(int fd, int action, const struct termios* termios_p);
    action 控制修改方式,有三种取值
    a.TCSANOW 立刻修改
    b.TCSADRAIN 等当前输出完成后再对值进行修改
    c.TCSAFLUSH 等当前输出完成后再对值进行修改,但是丢弃还没有从read调用返回的当前可用的任何输入。
    
    五种控制模式的取值可以查看手册,修改的时候选择对应的属性。下面简单说一下五种模式的功能或者呈现的效果
    a)输入模式:修改输入的各种模式,比如输入错误,产生一个中断信号,或者忽略某些符号。一般不需要修改,默认的最好
    b)输出模式:管理输出的模式,比如不输出某些字符,一般不需要修改。
    c).控制模式:控制硬件的终端。比如修改调制解调器
    d).本地模式:控制终端的各种特性,比如控制回显,接受各种动作的组合,启用标准输入处理,启用信号等
    e).特殊控制字符:主要是指输入的字符组合,比如Ctrl+C.它的控制有两种模式,一个是标准模式,另一个是非标准模式,它会根据本地模式,选择不同的模式。
    主要书向系统发送信号。
    



    (3)终端的速度。



    由于termios结构体没有关于速度的成员,因此专门设计了一组函数来控制终端的速度
    speed_t cfgetispeed(const struct  termios*)
    speed_t cfgetospeed(const struct termios*)
    int cfsetispeed(struct termios*, speed_t speed)
    int cfsetospeed(struct termios*, speed_t speed)
    速度都是有限制的,需要查看相关文档来设计
    



    (3)其他函数。


这些函数都是直接对文件描述符进行操作,而不是用termios结构体
    int tcdrain(int fd) 让调用程序一直等待,直到所有排队的输出都已经发送完毕
    int tcflow(int fd, int flowtype)用于暂停或者重新输入
    int tcflush(int fd)清空输入,输出

下面这个程序再输入密码的时候隐藏了显示,我们看不见输入了什么,输入结束后,我们重新恢复了回显,并输出了输入的密码在屏幕上


#include
#include
#include
#define PASSEDLEN 8//设置密码的固定长度int main()
{struct termios initialrsettings, newrsettings;char password[PASSEDLEN + 1];if( tcgetattr(fileno(stdin),&initialrsettings) == -1){fprintf(stderr,"获取失败\n");return 0;}newrsettings = initialrsettings;//设置终端回显,用到第五个元素,输入密码时不显示输入newrsettings.c_lflag &= ~ECHO;if(tcsetattr(fileno(stdin),TCSAFLUSH,&newrsettings) == -1){fprintf(stderr,"设置错误\n");return 0;}printf("请输入密码>>");fgets(password,PASSEDLEN,stdin);if(tcsetattr(fileno(stdin),TCSAFLUSH,&initialrsettings) == -1){fprintf(stderr,"设置错误\n");return 0;}printf("%s\n",password);return 0;
}

我们对上篇文章的程序修改,从终端入手解决读取缓存的问题

下面这个程序,我们设置每次只要读取到输入字符,就立刻返回程序 ,而不是等待回车换行符号才读取缓存


#include
#include
#include
#includechar *meun[]={"a = add new record","b - delete record","q - quit",NULL};int getchoice(char *greet, char* choices[], FILE* in, FILE* out);int main()
{int choice = 0;FILE* input,*output;struct termios initialSettings, newSettings;if(!isatty(fileno(stdout)))//判断输出是否被重定向fprintf(stderr,"这不是一个终端\n");elsefprintf(stderr,"输出重定向到了终端\n");input = fopen("/dev/tty","r");//读取终端output = fopen("/dev/tty","w");//写入终端if(!input || !output){perror("打开tty文件失败\n");return 0;}//先读取当前的终端状态if(tcgetattr(fileno(input),&initialSettings) < 0){fprintf(stderr,"获取失败\n");return 0;}newSettings = initialSettings;newSettings.c_lflag &= ~ICANON;//启用标准输入,只有启用了标准输入才能对特殊字符处理,比如换行符newSettings.c_lflag &= ~ECHO;//关闭回显newSettings.c_cc[VMIN] = 1;newSettings.c_cc[VTIME] = 0;newSettings.c_lflag &= ~ISIG;//屏蔽信号,即使是使用ctrl+c也不会终止程序//设置新的终端状态if(tcsetattr(fileno(input),TCSANOW,&newSettings) < 0){fprintf(stderr,"修改状态失败\n");return 0;}//进行本地设置do{choice = getchoice("请输入一个选择",meun,input,output);printf("您的选择是:%c\n",choice);}while(choice != 'q');//恢复为原来的默认状态if(tcsetattr(fileno(input),TCSANOW,&initialSettings) < 0){fprintf(stderr,"修改状态失败\n");return 0;}return 0;
}int getchoice(char* greet, char* choice[], FILE* input, FILE* output)
{int chosen = 0;int selected;char** option;do{fprintf(output,"choice:%s\n",greet);option = choice;while(*option){fprintf(output,"%s\n",*option);option++;}do{selected = fgetc(input);}while(selected == '\n' || selected == '\r');option = choice;while(*option){if(selected == *option[0]){chosen = 1;break;}option++;}if(!chosen)fprintf(stdout,"选择错误,请重新选择");}while(!chosen);return selected;
}

这个程序还屏蔽了某些信息的输入,这与信号函数不一样,这个是从输入进行屏蔽的,系统根本不会接受到我们输入信号 ,比如CTRL+C,输入后被认为是错误输入。

相关内容

热门资讯

马斯克即将创下的人类历史记录:...   炒股就看金麒麟分析师研报,权威,专业,及时,全面,助您挖掘潜力主题机会! (来源:网易科技)特...
三大世界级科创中心呼之欲出! ​​在当今世界百年未有之大变局加速演进、国际力量对比深刻调整的大背景下,外部环境不稳定、不确定因素明...
成都7宗涉宅用地14.94亿元... 格隆汇12月24日|12月24日,成都有7宗涉宅用地出让,其中双流区2宗(组合出让)、郫都区1宗、新...
严把质控关 守护“延安蓝”——... 来源:环球网 为进一步强化环境空气质量自动监测数据质量管控,规范环境空气质量自动监测站点运维管理,切...
海致科技冲刺港股:智能体收入暴... 主营业务:图模融合技术驱动增长,智能体成第二曲线但客户基数薄弱海致科技核心业务为提供Atlas图谱解...