0x05.I/O
*NIX/Linux追求高层次抽象上的统一,其设计哲学之一便是万物皆文件
一、“万物皆文件”
NIX/Linux设计的哲学之一——万物皆文件,在Linux系统的视角下,无论是文件、设备、管道,还是目录、进程,甚至是磁盘、套接字等等,一切都可以被抽象为文件,一切都可以使用访问文件的方式进行操作*
通过这样一种哲学,Linux予开发者以高层次抽象的统一性,提供了操作的一致性:
- 所有的读取操作都可以通过对文件进行 read 系统调用完成
- 所有的更改操作都可以通过对文件进行 write 系统调用完成
- 所有的配置操作都可以通过对文件进行 ioctl 系统调用完成
对于开发者而言,将一切的操作都统一于一个高层次抽象的应用接口,无疑是十分美妙的一件事情——我们不需要去理解实现的细节,只需要对"文件"完成简单的读写操作
例如,在较老版本的Linux中,可以使用
cat /dev/urandom > /dev/dsp命令令扬声器产生随机噪声

二、进程文件系统
进程文件系统(process file system, 简写为procfs)用以描述一个进程,其中包括该进程所打开的文件描述符、堆栈内存布局、环境变量等等
进程文件系统本身是一个伪文件系统,通常被挂载到/proc目录下,并不真正占用储存空间,而是占用一定的内存
当一个进程被建立起来时,其进程文件系统便会被挂载到/proc/[PID]下,我们可以在该目录下查看其相关信息
三、文件描述符
进程通过文件描述符(file descriptor)来完成对文件的访问,其在形式上是一个非负整数,本质上是对文件的索引值,进程所有执行 I/O 操作的系统调用都会通过文件描述符
每个进程都独立有着一个文件描述符表,存放着该进程所打开的文件索引,每当进程成功打开一个现有文件/创建一个新文件时(通过系统调用open进行操作),内核会向进程返回一个文件描述符
在kernel中有着一个文件表,由所有的进程共享
stdin、stdout、stderr
每个*NIX进程都应当有着三个标准的POSIX文件描述符,对应着三个标准文件流:
stdin:标准输入 - 0stdout:标准输出 - 1stderr:标准错误 - 2
此后打开的文件描述符应当从标号3起始
四、系统调用:ioctl
在*NIX中一切都可以被视为文件,因而一切都可以以访问文件的方式进行操作,为了方便,Linux定义了系统调用ioctl供进程与设备之间进行通信
系统调用ioctl是一个专用于设备输入输出操作的一个系统调用,其调用方式如下:
int ioctl(int fd, unsigned long request, ...)
- fd:设备的文件描述符
- request:请求码
- 其他参数
对于一个提供了ioctl通信方式的设备而言,我们可以通过其文件描述符、使用不同的请求码及其他请求参数通过ioctl系统调用完成不同的对设备的I/O操作
例如CD-ROM驱动程序弹出光驱的这一操作就对应着对“光驱设备”这一文件通过ioctl传递特定的请求码与请求参数完成