原文地址:彻底搞懂「一切皆文件」的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 表整个系统只有一个,它们三者之间的关系如下图所示。

img

4.2 文件描述符的本质

  从本质上讲,这三种表都是结构体数组,0、1、2、73、1976 等都是数组下标。表中不难看出文件描述符是进程文件描述符的数组。

  通过文件描述符,可以找到文件指针,从而进入打开文件表。该表存储了以下信息:

  • 文件偏移量,也就是文件内部指针偏移量。调用 read() 或者 write() 函数时,文件偏移量会自动更新,当然也可以使用 lseek() 直接修改。

  • 状态标志,比如只读模式、读写模式、追加模式、覆盖模式等。

  • i-node 表指针。

  打开文件表只是文件的中转站,通过打开文件表的 i-node 指针进入 i-node 表,该表包含了诸如以下的信息:

  • 文件类型,例如常规文件、套接字或 FIFO。

  • 文件大小。

  • 时间戳,比如创建时间、更新时间。

  • 文件锁。

4.3几种文件描述符情景

  1. 同一个进程的不同文件描述符可以指向同一个文件;(可能是通过调用 dup()、dup2()、fcntl() 或者对同一个文件多次调用了 open() 函数形成的。 )
  2. 不同进程可以拥有相同的文件描述符;(描述符正好分配到与其他进程打开该文件的描述符一样)
  3. 不同进程的同一个文件描述符可以指向不同的文件(一般也是这样,除了 0、1、2 这三个特殊的文件);
  4. 不同进程的不同文件描述符也可以指向同一个文件。(每个进程各自对同一个文件发起了 open() 调用。同一个进程两次打开同一个文件,也会发生类似情况)

4.4 socket 文件描述符

  通过上面的知识,我们可以知道socket其实也是个文件,只不过这个文件用来进行网络通信的。我们获得sokcet的fd后,通过fd作为参数调用其他函数达到通信的目的。   fd本质上更像win中的句柄,是内核提供给用户来安全地操作文件的标识,不像指针,拥有了指针后你能瞎JB改。拥有了描述符后,你只能传入描述符给特定的接口,实际操作由内核读取用户输入的参数后来安全地执行。

(完)