[转]彻底搞懂「一切皆文件」的UNIX哲学
原文地址:彻底搞懂「一切皆文件」的UNIX哲学
作者: uianster
一、UINX哲学
一切皆文件是 Unix/Linux 的基本哲学之一。不仅普通的文件,目录、字符设备、块设备、 套接字等在 Unix/Linux 中都是以文件被对待;它们虽然类型不同,但是对其提供的却是同一套操作界面。
二、UNIX文件类型
下面列举了UNIX中常用到的文件类型,其实除了普通文件以外,其他的其实都不是真正意义上的文件。
三、查看进程文件
UNIX中提供一个文件作为我们对其操作的入口。有些文件我们甚至可以使用命令直接查看其内容。下面我们以查看进程文件为例子。
local@local-PC:~$ ps|grep 11329 # 找到我们的例子进程
11329 pts/3 00:00:00 bash
local@local-PC:~$ cd /proc/ # 进入proc中
local@local-PC:/proc$ ls -l |grep 11329 # 找到对应pid的文件夹
dr-xr-xr-x 9 local local 0 9月 28 14:08 11329
local@local-PC:/proc$ cd 11329 # 进入对应pid的文件夹
local@local-PC:/proc/11329$ ls
attr comm fd map_files net pagemap schedstat stat timerslack_ns
autogroup coredump_filter fdinfo maps ns patch_state sessionid statm uid_map
auxv cpuset gid_map mem numa_maps personality setgroups status wchan
cgroup cwd io mountinfo oom_adj projid_map smaps syscall
clear_refs environ limits mounts oom_score root smaps_rollup task
cmdline exe loginuid mountstats oom_score_adj sched stack timers
local@local-PC:/proc/11329$ cd fd
local@local-PC:/proc/11329/fd$ ls -l # 查看本进程的所有文件描述符号
总用量 0
lrwx------ 1 local local 64 9月 28 14:08 0 -> /dev/pts/3
lrwx------ 1 local local 64 9月 28 14:08 1 -> /dev/pts/3
lrwx------ 1 local local 64 9月 28 14:08 2 -> /dev/pts/3
lrwx------ 1 local local 64 9月 28 14:10 255 -> /dev/pts/3
local@local-PC:/proc/11329/fd$ cd .. #可以通过该文件内存映射详细信息
local@local-PC:/proc/11329$ cat smaps
00400000-00500000 r-xp 00000000 08:03 6684751 /usr/bin/bash
Size: 1024 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 948 kB
Pss: 506 kB
Shared_Clean: 884 kB
Shared_Dirty: 0 kB
Private_Clean: 64 kB
Private_Dirty: 0 kB
Referenced: 948 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 506 kB
VmFlags: rd ex mr mw me dw sd
netstat -anpt |grep 22
lsof -p 27534 //用lsof查看该进程的所有文件描述符,其中的type字段就是表明它是什么类型,通过man losf
四、Linux 文件描述符到底是什么?
在编程中对上述的文件、设备、socket我们通常都可以使用open函数打开,open给我们返回一个fd(文件描述符),那么这个fd究竟是啥?
4.1 进程与文件描述符的关系
一个 Linux 进程启动后,会在内核空间中创建一个 PCB 控制块,PCB 内部有一个文件描述符表(File descriptor table),记录着当前进程所有可用的文件描述符,也即当前进程所有打开的文件。 除了文件描述符表,系统还需要维护另外两张表:
-
打开文件表(Open file table)
-
i-node 表(i-node table)
文件描述符表每个进程都有一个,打开文件表和 i-node 表整个系统只有一个,它们三者之间的关系如下图所示。
4.2 文件描述符的本质
从本质上讲,这三种表都是结构体数组,0、1、2、73、1976 等都是数组下标。表中不难看出文件描述符是进程文件描述符的数组。
通过文件描述符,可以找到文件指针,从而进入打开文件表。该表存储了以下信息:
-
文件偏移量,也就是文件内部指针偏移量。调用 read() 或者 write() 函数时,文件偏移量会自动更新,当然也可以使用 lseek() 直接修改。
-
状态标志,比如只读模式、读写模式、追加模式、覆盖模式等。
-
i-node 表指针。
打开文件表只是文件的中转站,通过打开文件表的 i-node 指针进入 i-node 表,该表包含了诸如以下的信息:
-
文件类型,例如常规文件、套接字或 FIFO。
-
文件大小。
-
时间戳,比如创建时间、更新时间。
-
文件锁。
4.3几种文件描述符情景
- 同一个进程的不同文件描述符可以指向同一个文件;(可能是通过调用 dup()、dup2()、fcntl() 或者对同一个文件多次调用了 open() 函数形成的。 )
- 不同进程可以拥有相同的文件描述符;(描述符正好分配到与其他进程打开该文件的描述符一样)
- 不同进程的同一个文件描述符可以指向不同的文件(一般也是这样,除了 0、1、2 这三个特殊的文件);
- 不同进程的不同文件描述符也可以指向同一个文件。(每个进程各自对同一个文件发起了 open() 调用。同一个进程两次打开同一个文件,也会发生类似情况)
4.4 socket 文件描述符
通过上面的知识,我们可以知道socket其实也是个文件,只不过这个文件用来进行网络通信的。我们获得sokcet的fd后,通过fd作为参数调用其他函数达到通信的目的。 fd本质上更像win中的句柄,是内核提供给用户来安全地操作文件的标识,不像指针,拥有了指针后你能瞎JB改。拥有了描述符后,你只能传入描述符给特定的接口,实际操作由内核读取用户输入的参数后来安全地执行。
(完)