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\n",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\n",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\n",ttyinfo.c_cc[VERASE],ttyinfo.c_cc[VERASE]);
show_someflag(&ttyinfo); //显示当前终端的一些设置信息
return 0;
}
void showbaud(int speed)
{
printf("the baud rate is %d .\n",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.\n"); //判断该属性是否已经打开
else printf("off.\n");
}
}
void show_someflag(struct termios *termios_p)
{
printf("display some flag as follow:\n");
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.\n");
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;
}