stty用于改变和显示终端的设置信息,准确的说是改变终端驱动程序的设置信息.tty的驱动程序位于内核,内核用于连接外部世界(磁盘文件、设备文件)与进程间的数据交换.而tty也属于设备文件中的一种,
现在介绍两种操作磁盘文件的方式,分别采用系统的函数调用和C语言的库函数调用.
第一种:系统库函数
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define LENGTH 100 int main() { int fd,len; char str[LENGTH]; char *content="undergrowth"; fd=open("un.txt",O_CREAT | O_RDWR,S_IRUSR|S_IWUSR); if(fd) { write(fd,content,strlen(content)); close(fd); }else { exit(0); } fd=open("un.txt",O_RDONLY); len=read(fd,str,LENGTH); printf("%s ",str); close(fd); return 0; }使用 gcc -Wall hello.c -o un 编译即可 运行 ./un
上面使用open以所有者可读可写的权限来操作un.txt文件 使用write写完数据后 关闭文件描述符
第二种方式:C语言的库函数
#include <stdio.h> #define LENGTH 100 int main() { FILE *fd; char str[LENGTH]; char *content="undergrowth"; fd=fopen("un.txt","w+"); if(fd) { fputs(content,fd); fclose(fd); } fd=fopen("un.txt","r"); fgets(str,LENGTH,fd); printf("%s ",str); fclose(fd); return 0; }
使用 gcc -Wall hello.c -o un 编译即可 运行 ./un
上面使用fopen以读写的方式打开un.txt,如果不存在,则进行创建,然后使用fputs向磁盘文件中写入数据,之后在使用fgets从磁盘文件中获取LENGTH长度的字符放入str字符数组中
接下来介绍tty设备文件
磁盘文件与设备文件有很多相似的地方,比如都有文件的属性、文件的大小、文件的修改时间、文件的节点等等之类的,都可用系统的库函数与C语言的库函数来进行open、read、write、close、ioctl来进行操作。
那么内核如何区分文件时磁盘文件还是设备文件呢?
这里就要看磁盘文件和设备文件共有的一个属性即文件节点,当内核要准备为文件读数据时,首先会看文件的文件节点属性,如果文件节点对应的是磁盘文件的话,则直接根据文件系统的映射表读取数据,如果是设备文件的话,则会调用设备文件的驱动程序的read方法进行读取.
磁盘文件在进行读写的时候是有缓冲区的,而设备文件是没有缓冲区的.
而对于tty设备文件,我们可以通过tcgetattr、tcsetattr来对其驱动程序的属性进行读取和重新设置,从而影响其正常的工作.
下面是一个显示tty驱动设备的属性的小程序,只显示了几个比较重要的属性,更多的可以使用man tcgetattr来进行查看
#include <stdio.h> #include <termios.h> #include <stdlib.h> #define eops(s,x) {perror(s); exit(x);} int main() { struct termios ttyinfo; void showbaud(int); void show_someflag(struct termios *); if((tcgetattr(0,&ttyinfo))==-1) eops("tcgetattr",1); //获取到当前终端的设置信息保存在ttyinfo结构体中 showbaud(cfgetospeed(&ttyinfo)); //显示输出波特率 printf("the erase charcter is ascii %d,Ctrl-%c ",ttyinfo.c_cc[VERASE],ttyinfo.c_cc[VERASE]); show_someflag(&ttyinfo); //显示当前终端的一些设置信息 return 0; } void showbaud(int speed) { printf("the baud rate is %d . ",speed); } struct flaginfo { //用于保存属性名及其描述 int fl_value; char *fl_desc; }; struct flaginfo input_flag[]={ //构建输入属性 {IGNBRK,"ignore break condition"}, {INLCR,"map nl to cr on input"}, {IXOFF,"enable start/stop input control"}, {0,NULL} }; struct flaginfo output_flag[]={ //构建输出属性 {OLCUC,"map lowercase character to uppercase character on output"}, {0,NULL} }; struct flaginfo local_flag[]={//构建本地属性 {ECHO,"echo input character"}, {ISIG,"when any on character intr,quit,susp or dsusp are received,generate the corresponing the signal"}, {0,NULL} }; struct flaginfo control_flag[]={//构建控制属性 {CREAD,"enalbe receiver"}, {CRTSCTS,"enable rts/cts flow control"}, {0,NULL} }; void show_flagset(int thevalue,struct flaginfo fi[]) { int i; for(i=0;fi[i].fl_value;i++) { printf(" %s is ",fi[i].fl_desc); if(fi[i].fl_value&thevalue) printf("on. "); //判断该属性是否已经打开 else printf("off. "); } } void show_someflag(struct termios *termios_p) { printf("display some flag as follow: "); show_flagset(termios_p->c_iflag,input_flag); show_flagset(termios_p->c_oflag,output_flag); show_flagset(termios_p->c_lflag,local_flag); show_flagset(termios_p->c_cflag,control_flag); }
还有一个是两个终端进行相互通信
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <string.h> //#define BUFSIZ 30 int main(int argc,char *argv[]) { int fd; char buf[BUFSIZ]; if(argc!=2) { perror("usage:write ttyname. "); exit(1); } fd=open(argv[1],O_WRONLY); //获取另外一个终端的名字 if(fd==-1) { perror(argv[1]); exit(1); } while(fgets(buf,BUFSIZ,stdin)!=NULL)//从当前终端获取信息 { if(write(fd,buf,strlen(buf))==-1) break; //将信息写入到另外一个终端 } close(fd); return 0; }