0.摘要
本章主要的概念与技巧
·文件和设备相似之处
·文件和设备不同之处
·连接的属性
·竞争和原子操作
·控制设备驱动程序
·流
相关的系统调用
·fcntl,ioctl
·tcsetattr,tcgetattr
相关命令
·stty
·write
1.设备就像文件
在Unix中,声卡,终端,鼠标等设备和磁盘文件是同一种对象。在Unix系统中,每个设备都被当做一个文件。每个设备都有一个文件名、一个i-节点号、一个文件所有者、一个权限位的集合和最近修改时间。接下来具体看一下设备文件的表示
1.1.1设备具有文件名
可以通过一下命令来查看设备属性:
$ ls -C /dev |head -5
autofs lightnvm sda6 tty25 tty58 ttyS31
block log sda7 tty26 tty59 ttyS4
bsg loop0 sdb tty27 tty6 ttyS5
btrfs-control loop1 sdb1 tty28 tty60 ttyS6
bus loop2 sdb2 tty29 tty61 ttyS7
第一列表示设备名,第二列表示所属的类别,第三列表示sd*文件是SCSI设备的分区。
1.1.2设备和系统调用
从对于设备文件的操作角度来看,允许所有文件操作:open,read,write,lseek,close和stat,通过这样的操作就可以调用/dev下的设备的内容。
1.1.3举个例子:终端设备
终端设备就像文件一样,它是接收用户字符输入和将输出信息显示给用户的。例如:
$ cp /etc/modules /dev/pts/21
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
$ ls -li /dev/pts/21
24 crw--w---- 1 shengchen tty 136, 21 12月 23 16:06 /dev/pts/21
它就像文件一样,可以进行任何文件可以进行的操作。
1.1.4 设备文件的属性
(1)设备文件和文件大小
(2)设备文件和权限位
这些设备文件是怎么工作的呢?Unix文件系统的i-节点和数据块是如何支持设备文件这个概念的?
和文件一样,设备文件也是通过在目录中找到对应i节点号,然后再去找i节点中的信息,这里的查找到的信息有所不同,stat内容不同,其中st_mode是主要区分的地方。这里以read为例,在inode节点中找到信息,用于告诉内核调用什么文件类型,如果是文件,则访问块分配表来读写数据。如果是设备文件,则调用设备驱动程序的read。其他的操作也相同,如open,write,lseek和close等。
接下来来谈谈具体的属性以及区别
2.磁盘连接的属性
2.1.1属性1:缓冲
fctnl系统调用可以读写文件的属性,来控制文件描述符。
#include<fcntl.h>
int s; //setting
s = fcntl(fd, F_GETFL); //get flags
s | = O_SYNC; //set SYNC bit
result = fcntl(fd, F_SETFL,s); // set flags
if(result == -1) //if error
perror("setting sync"); //report
上述 操作中位逻辑或操作打开了O_SYNC,告诉内核,对write的调用仅能在数据写入实际的硬件时才能返回,要等待一个同步的过程。
这里面有三个过程(从内核中读入设备的变量,修改这些变量,返回变量给内核)。设置O_SYNC会关闭内核的缓冲机制。这说明,默认情况下读入文件是缓冲读入的。
2.1.2属性2:自动添加模式
自动添加模式对于若干个程序同一时间写入文件很有用。如下的代码就是自动添加的操作,目的是为了避免竞争的出现。
#include<fcntl.h>
int s; //setting
s = fcntl(fd, F_GETFL); //get flags
s | = O_APPEND; //set APPEND bit
result = fcntl(fd, F_SETFL,s); // set flags
if(result == -1) //if error
perror("setting APPENDING"); //report
else
write(fd,&rec,1); //write record at end
这里通过添加了O_APPEND模式来将lseek和write 绑定在一起,这样多个用户登录的时候,不会导致日志的覆盖问题了。
绑定是为了避免出现lseek查找到结尾后,程序1还没有写入,程序2也改变了lseek,并且写入内容到文件中,这样程序1再写就会覆盖之前的内容。
以上的这两个属性可以在fd的基础上进行操作,也可以在open的时候直接打开,详见man手册。
3.终端连接的属性
ps:在终端按下Enter键或Return键通常发送ASCII码13,即回车符。但是当程序运行输出之后,返回的ASCII码被替换成10(换行符)
3.1.1终端驱动程序
处理进程和外部设备间数据流的内核子程序的集合称为终端驱动程序或tty驱动程序。如将回车输入的变成换行符。输出有将若干个空格来代替制表符,将换行符转换位回车符
3.1.2stty命令
stty是用来显示和修改终端行信息。
通过stty就可以改变一些操作。
3.1.3 编写终端驱动程序:关于函数
通过以下函数可以得到和设置终端驱动程序的属性,
tcgetattr(int fd, struct termios *info);
tcsetattr(int fd,int when, struct termios * info); //when表示什么时候设置写hui
3.2其他设备程序:ioctl
可以改写和查看其他设备的属性
3.3文件,设备和流
流模型的一个重要特征就是处理的模块化。不满意某个操作,可以将这个流模型转换成另一个