当前位置:网站首页 > 经验分享 > 正文

Linux内核设计与实现

原视频地址:www.youtube.com/watch?v=Ftg…

本文内容概览:

  • 文件描述符
  • 操作系统基础
  • 文件描述符和进程
  • 网络和 sockets

文件描述符

相信你对"On Unix, Everything is a file"已经耳熟能详了,比如/dev目录、/proc目录等,你几乎可以通过操作文件的方式获取系统所有能够获取的data。而和文件进行交互,就需要用到文件描述符(file descriptors,简称 fd,就是一个数字,在某个进程内唯一)。

通过文件你能完成这些事。

形象点来说,文件描述符就像是一张门票,每次你需要完成某种操作的时候,就把这张门票给操作系统,然后操作系统为你完成你想要做的。

有几个系统定义的标准文件描述符:

  • 0:标准输入,对应 Python 的 sys.stdin
  • 1:标准输出,对应sys.stdout
  • 2:标准错误输出,对应sys.stderr

然后我们通过几个例子来巩固一下:

with open('example.txt') as f: print(f.read()) 

上面这个程序用到了两个 fd,一个是 open 函数创建的,另一个是 print 的时候用到了标准输出的 fd,也就是1。

你还能根据 fd 修改文件的权限:

with open('example.txt') as f: stat = os.stat(f.fileno()) os.chmod(f.fileno(), 0o640) 

甚至还能控制硬件:下面的这段代码可以用来弹出 CDROM。

操作系统基础

在黑暗的中世纪。。。应用程序是可以直接操控硬件的,这意味着程序如果crash 了,会把整个系统搞垮,然后就需要重启电脑。

现在多亏了操作系统这一环,实现了隔离效果,应用程序将不能直接访问硬件,必须通过系统调用的方式向操作系统申请对硬件资源的访问。操作系统有一套权限管理机制,可以选择不接受你的请求。

syscall

每次 syscall,都会从 user space 转到 kernel space,运行完了再转回 user space。这意味着需要进行 context switch,所以速度相对而言是较低的(需要的时钟周期数为百数量级)。

回到之前的那个例子:

# read.py with open('example.txt') as f: print(f.read()) 

有一个工具可以查看某个程序调用了syscall:

$ strace ./read.py 

open file table 和 fd table

open file table 是一个全局的,所有进程打开的文件都在这里。每个进程有一个自己的 fd table,实际上也是指向了 open file table:

同一个进程第二次打开同一个文件,fd 不一样。

fd table的内容很简单,实际的详细数据保存在open file table。

fork()

fork 创建一个子进程,子进程会继承父进程的 fd,同时以copy opn write的方式基础父进程的内存,事实上可以看作是内容和父进程完全一致。继承 fd 意味着:

pid = os.fork()之后,子进程继承了父进程的文件描述符:上面的 f,他们指向的是 open file table中同一个文件,这意味着他们的 offset 都是一样的:

exec()

替换当前程序的内存,fd 也是会被继承的,除非设置了cloexec。子进程继承父进程的 fd 是存在一定问题的,这实际上相等于是把父进程的 fd 泄露给了子进程,会带来一定的安全隐患。所以有人起草了pwp446提案,提供了一个关闭父进程 fds 的选项:subprocess模块有一个close_fds参数,设置为True就表示调用exec的时候,把除了0,1,2三个 fds 之外的 fds 全部关闭掉。详细信息可以看看pep446原文和subprocess的官方文档。

网络和 sockets

要进行网络通信,需要一对 network socket,一个运行在服务器,一个在客户端。服务器端的 socket进程一般绑定在特定的端口,比如80,3306, 5432等等,它会一直监听在这个端口,监听到请求之后触发相应的逻辑,。最后会把结果返回给客户端。客户端的 socket 一般会临时绑定一个高段位的端口,请求结束之后(也就是进程结束)就会取消榜单,释放珍贵的端口资源。

Python 中的socket模块,主要需要指定两个参数:选择 IPV4还是 IPV6,使用 UDP 还是 TCP?一个简单的 server 示例:

client 示例:

unix sockets

unix sockets 和 network sockets 其实差不多,只不过只能让同一台 machine 上的进程进行通信。UNIX domain socket的一方知道对方进程在一台机器上,所以可以不用诸如检验措施、路由操作等操作,所以相对而言更加快和轻量级。

在 Python 中是这样使用的:bindconnect的现在不是 IP 地址和端口号了,而是文件。因为是文件,所以可以设置读写权限! 比如你可以限制某个特定组的用户才能从这个 socket 里面读数据。

如果你像我一样真正热爱计算机科学,喜欢研究底层逻辑,欢迎关注我的微信公众号:

版权声明


相关文章:

  • iOS支付功能篇:原生WebView调起支付宝客户端支付方案2025-01-06 23:30:00
  • 支付宝Appid2025-01-06 23:30:00
  • Ubuntu配置静态IP2025-01-06 23:30:00
  • Ubuntu 20.04 升级最新内核、安装指定内核版本2025-01-06 23:30:00
  • 安卓手机如何改ip地址教程2025-01-06 23:30:00
  • vscode读linux源码,vscode搭建linux内核开发环境2025-01-06 23:30:00
  • 原神私人服务器部署教程(Win)2025-01-06 23:30:00
  • 单片机:基础知识2025-01-06 23:30:00
  • (超详细)手把手教你在安卓手机上搭建服务器和网站2025-01-06 23:30:00
  • 单片机怎么实现模块化编程?思维+实例+系统教程(实用程度令人发指)2025-01-06 23:30:00