xiaohanliang
OS
OS
  • hi
  • PROCESS
    • 0. 你的程序是怎么用内存的
    • 1. 为什么内存要区分堆与栈
    • 2. 什么叫你的程序
    • 3. 搞玄学?看看进程切换
    • 4. 进程是怎样调度的
    • 5. 理解进程线程有啥用
    • 6. 没有人真正见过的进程通信
    • 7. [WIP]mutex的起源CAS
    • 8. [WIP]mutex的下一步信号量
    • 9. [WIP]如何人为制造死锁
    • 10. 怎么什么东西都是fd
    • 11. IO各种模型
    • 12. Epoll内部是怎么工作的
  • NETWORK DEVICES
    • 1. 一个新的namesapce
    • 2. veth对讲机
    • 3. 如何靠网桥连接对讲机
    • 4. 左耳进右耳出的tun设备
    • 5. 如何用iptables改包头
    • 6. 在ip报头上再包个头
    • 7.如何用vxlan隧道分割局域网
    • 8. 通过多播组的方式获取mac
    • 9. 自动维护的fdb/arp表
    • 10. [WIP]macvlan网卡
Powered by GitBook
On this page
  • introduction
  • FD是一个指向内核的指针
  • FD是如何诞生的
  • 那FD是如何跟文件系统挂钩的

Was this helpful?

  1. PROCESS

10. 怎么什么东西都是fd

Previous9. [WIP]如何人为制造死锁Next11. IO各种模型

Last updated 4 years ago

Was this helpful?

introduction

想要深刻理解epoll是怎么工作的, 就必须先对fd有一个深刻的理解

一个程序是怎么跟文件系统挂钩的, 为什么一个程序能通过一个文件描述符控制文件.

一个进程能通过"描述符"控制IO-stream, 无论你怎么看, 文件, socket, tty 在本质上都是一种IO-stream, 因为我们都可以从这三者里取出byte数组, 因此在操作系统眼里看来你们都是byte数组的提供方, 就都可以用 fd 指代. 那我们今天要解释的问题就是进程是如何通过fd指代到文件的.

FD是一个指向内核的指针

每一个进程都会维护一个table, 里面维护了他要访问的fd, 一个fd既可以通过open / pipe / socket 这样的方式显式的创建出来, 同时可以是从父进程那里继承过来的. 但总之他有一张表, 里面罗列了所有的fd. 我们从上面的图看下一个 fd 主要还是由一个 file-pointer 指针所定义

FD是如何诞生的

那么详细来说 fd到底是什么? Kernel维护了一个 OPEN FILE TABLE, 你如果开一个文件, 这个表里就会多出一项, 而fd, 即file-pointer就是指向这个[表项]的指针. 以上这句话, 直接说明了:

  1. fd是什么: 是一个指针, 指向内核维护的文件表项

  2. 为什么fd进程独享吗?:

    1. 因为OPEN FILE TABLE 记录的了 [谁, 什么文件], 你的进程打开以后这个表项就是 [你, 文件A] , 当然别人也可以打开同一个文件A,那么表里会再生成一项: [他, 文件A] , 但这是另一个表项了, 因此它会拿到另一个fd, 因此我们说同一个进程下不同的线程拿到的是同一个fd

    2. 但通过复制可以拿到两个fd, 指向同一个文件表项 / 子进程通过继承拿到父进程的表项 / 不同进程之间可以通过某种Socket互传fd, 在上面的图中进程A先打开了一个文件, 生成了一个fd0, 接着我们复制这个fd0(文件描述符的复制), 得到了fd3, 接着fork出进程B, 进程B继承了父进程的fd0. 因此不是进程独享的

那FD是如何跟文件系统挂钩的

我们注意看一下上面的表项, 里面是不是有一项叫做inode, 这个概念你应该在硬链/软链见过一次, 一个inode号:

  • 文件的 磁盘块 位置

  • 文件格式, 归属权, 路径等meta信息

那么简单来说, fd → 内核文件表项 → inode → 文件系统, 你可以通过ls -i看看文件的inode号. 每个文件(的入口位置)都有一个inode, 因此ls -i出来的文件inode号其实就是文件入口的inode号.

在上面的图中, fd0/3因为是复制出来的, 因此指向同样的内核表项, 因此指向同样的inode. 而fd5是进程A打开的另一个文件, 因此指向了另一个inode号, 另一个文件