Linux 一切皆文件的本质
Linux 一切皆文件的本质插U盘是/dev/sdb连串口是/dev/ttyUSB0读键盘是/dev/input/event0。Linux 为什么把所有东西都叫“文件”因为键盘、网络、定时器、进程信息最终都变成一个 fdselect / poll / epoll 用一个循环就能全部监听。这其实是它最顺手的设计之一。一、先看现象 /dev 下为什么全是硬件第一次打开 Linux 的/dev目录很多人会愣住$ ls /devsda sdb ttyUSB0 input null zero random这里没有文档、没有图片却列着硬盘、串口、键盘、随机数发生器。更奇怪的是你可以像读文件一样读键盘$ sudo cat /dev/input/event0按下回车屏幕刷出一堆乱码——那就是按键事件。在 Linux 看来键盘不过是一个可读的数据流。本节要点Linux 把硬件、内核对象、进程信息都放进/dev、/proc、/sys打开它们就像打开普通文本。二、Linux 里的“文件”到底是什么我们平时说的“文件”指硬盘上的数据比如.txt、.mp4。但 Linux 的“文件”是更宽泛的抽象文件 一段可以通过 open / read / write / close 访问的数据流。数据存在磁盘、来自键盘缓冲区、还是内核实时生成都不重要。重要的是接口统一。类型例子数据来源占磁盘吗普通文件/home/user/note.md磁盘块是设备文件/dev/sda、/dev/ttyUSB0硬件驱动否输入事件/dev/input/event0内核输入子系统否伪文件/proc/cpuinfo、/sys/class/gpio内核实时生成否套接字socket()返回的 fd网络协议栈否本节要点Linux 的“文件”是接口抽象不是磁盘文件。能用四个基本动作访问的数据流都可以叫文件。三、键盘、鼠标、网络为什么都是文件3.1 键盘鼠标裸机读取键盘要处理中断、扫描码、消抖Windows 要调专门 API。Linux 只需要int fd open(/dev/input/event0, O_RDONLY);struct input_event ev;read(fd, ev, sizeof(ev));一个read()拿到按键的时间戳、键码、按下/松开状态。鼠标滚轮、坐标、点击同理。平台读键盘需要做什么裸机/MCU中断、扫描码、消抖WindowsRaw Input / DirectInput APILinuxopen()read()/dev/input/eventX把输入设备做成文件应用层就不用再背一套新 API。3.2 网络socket 本质上也是文件描述符int sock socket(AF_INET, SOCK_STREAM, 0);write(sock, hello, 5);read(sock, buf, sizeof(buf));close(sock);高并发服务器里每个连接就是一个 fd全部交给epoll_wait统一监听。一个线程管几万个连接靠的就是这个抽象。本节要点键盘鼠标是事件流文件网络是双向字节流文件。应用层只关心 fd 里读到了什么。四、/proc 和 /sys 也是文件/proc没有真正的磁盘文件内容都是内核实时生成$ cat /proc/cpuinfo # CPU 信息$ cat /proc/meminfo # 内存使用$ cat /proc/1234/status # 进程状态$ ls /proc/1234/fd # 进程打开的文件描述符/sys更偏向设备和驱动属性。操作 GPIO 就是写文件$ echo 17 /sys/class/gpio/export$ echo out /sys/class/gpio/gpio17/direction$ echo 1 /sys/class/gpio/gpio17/value路径用途/proc/cpuinfo看 CPU 型号、核心数/proc/PID/fd排查句柄泄漏/sys/class/gpio用户态控制 GPIO/sys/class/net/eth0看网卡 MAC、MTU本节要点进程、内存、CPU、GPIO 都被抽象成文件用户空间用最普通的open/write就能访问内核数据。五、这种设计带来什么好处Unix 哲学里有一条一切皆文件所有工具只做一件事程序之间用文本流协作。Linux 继承了这个思路。5.1 统一接口不管对方是硬盘、键盘、网卡还是内核对象open / read / write / close / epoll 足够应付大多数场景。学一套接口管几乎所有资源。5.2 组合性极强因为接口统一任何产生数据的“文件”都能进管道$ cat /proc/cpuinfo | grep model name | sort | uniq -c5.3 权限模型复用文件权限系统直接套在设备文件上$ ls -l /dev/ttyUSB0crw-rw---- 1 root dialout 188, 0 Jul 8 10:00 /dev/ttyUSB0只有dialout组能访问串口不用额外写权限逻辑。5.4 多路复用简单select / poll / epoll监听的是 fd。socket、timerfd、signalfd、eventfd 都是 fd一个事件循环就能统一管理所有输入来源。本节要点一切皆文件带来统一接口、管道组合、权限复用、epoll 统一监听四大好处。六、注意边界“一切皆文件”是接口统一不是语义完全相同坑现象解法对 socketlseek()返回 ESPIPEsocket 不支持 seek普通文件 fd 塞进 epollepoll_ctl报 EPERM普通文件没有“就绪”概念以为/proc内容固定两次读取结果不同动态生成读一次用一次读/dev/input/event0没权限Permission denied加入input组或用 sudo对/sys写错值驱动报错先cat看当前值再写本节要点统一的是访问接口不是语义。读写时仍要尊重每个对象的本性。七、总结Linux 的“一切皆文件”本质是把所有资源都抽象成字节流。不是说所有东西都是磁盘文件而是说只要用 open / read / write / close 这套语言描述键盘、鼠标、网络、进程、GPIO 都能被统一访问。