本文发表在 Linux 杂志上。作者从技术角度深入解释了 Linux 的工作原理。相信对Linux开发者会有很大的帮助。
《牛津词典》中“”的定义是:“坚果中较软、通常可食用的部分。”当然,还有第二个定义:“某事物的核心或最重要的部分”。对于Linux来说,无疑属于第二种解释。让我们从一些理论开始,看看这个重要的东西是如何工作的。
从广义上讲,它是一个软件,在硬件和计算机上运行的应用程序之间提供了一个层。严格来说,从计算机科学的角度来看,Linux 指的是 Linus 在 20 世纪 90 年代初编写的代码。
您在 Linux 发行版中看到的所有其他内容 - Bash shell、KDE 窗口管理器、Web 浏览器、X 服务器、Tux Racer 等等 - 都只是在 Linux 上运行的应用程序,而不是操作系统本身的一部分。为了给大家一个更直观的感受,我举个例子。例如,RHEL5的安装将占用大约2.5GB的硬盘空间(具体大小当然取决于您选择的安装)。其中,以及其各个模块组件,仅47MB,占比约2%。
里面
那么它到底是如何运作的呢?如下图所示。在其上运行的应用程序可以通过许多入口端口访问,这在技术上就是我们所说的系统调用。使用“read”和“write”等系统调用为您提供硬件()的抽象。
从程序员的角度来看,这些看似只是普通的函数调用,但实际上系统调用在处理器的操作模式从用户空间到空间之间有明显的切换。同时,系统调用提供了一个“Linux虚拟机”,可以将其视为硬件的抽象。
提供的更明显的抽象之一是文件系统。例如,下面是一个用 C 编写的简短程序,它打开一个文件并将其内容复制到标准输出:
#
int main()
int fd,计数;字符缓冲区[1000];
fd=打开("", );
计数 = 读取(fd, buf, 1000);
写(1,buf,计数);
关闭(fd);
在这里您可以看到四个系统调用的示例:打开、读取、写入和关闭。无需深入讨论该程序的语法细节,要点是:通过这些系统调用,Linux 提供了文件的“幻象”,而实际上它只是一堆带有名称的数据,因此您不会必须与底层硬件打交道,而不是协商堆栈、分区、头、指针、分区等,而是直接按照示例中的方式与硬件“通信”。这就是我们所说的抽象(),用更容易理解的方式表达底层的东西。 。
幕后花絮
系统文件是提供的更明显的抽象之一。还有一些功能不是那么明显,比如进程调度。在任一时刻,可能有多个进程或程序等待运行。时间调度将CPU时间分配给每个进程,因此在一段时间内,我们会产生计算机同时运行多个程序的错觉。这是另一个 C 程序:
#
主要的()
如果(叉()){
写(1,“/n”,7);
等待(0);
退出(0);
别的 {
write(1, "孩子/n", 6);
退出(0);
在这个程序中,创建了一个新进程,原进程(父进程)和新进程(子进程)都写入标准输出,然后终止。注意系统调用fork()、exit()、wait()执行各个程序的创建、结束和同步。这是进程管理和调度中最典型的简单调用。
还有一个功能,即使对于程序员来说,也是更加难以见到的,那就是存储管理。每个程序运行时就好像它有自己的地址空间可以调用一样。事实上,它与其他进程共享计算机的物理存储。如果系统运行在太低的存储上,其地址空间甚至可能被磁盘的交互区域阻塞。暂时发布。存储管理的另一个方面是防止一个进程访问另一个进程的地址空间——这是多进程操作系统的必要预防措施。
还配置了IP、TCP和UDP等网络链接协议,提供网络上机器对机器(-to-)和进程对进程(-to-)的通信。这将造成一种错觉,即 TCP 在两个进程之间提供了固定连接 - 就像连接两部电话的铜线一样。其实并没有什么固定的联系。 FTP、DNS 和 HTTP 等特殊参考协议是由用户级程序实现的,不属于 的一部分。
Linux(就像之前的 Unix)在安全性方面享有良好的声誉,因为每次应用程序尝试访问资源(例如打开文件进行写入)时,它都会跟踪每个正在运行的进程的用户 ID 和组 ID,并且会检查文件的访问权限并发出允许/禁止命令。这种访问控制模型最终对整个Linux系统的安全起到了很大的作用。
它还提供了大量的模块集合,用于处理如何与硬件设备通信、如何从磁盘读取分区、如何从网络接口卡获取数据包等细节。有时我们将这些称为设备驱动程序。
模块化的
现在我们对我们团队的工作有了一些了解,让我们简单看一下它的物理构成。 Linux 的早期版本是整体的,这意味着所有组件都静态链接到一个(大)可执行文件中。
相比之下,今天的Linux是模块化的:许多功能都包含在模块中,然后动态加载。这使内核保持较小,并允许在运行时加载和替换模块,而无需这样做。
内核在引导时从位于 /boot 目录中的文件加载到存储中。通常会根据版本调用此 /boot 目录。 (如果您想知道您的版本,请运行命令行 show info -r。)模块位于目录 /lib// 中,所有组件将在安装过程中复制。
管理模块
在大多数情况下,Linux 无需您的帮助即可管理其模块,但如有必要,可以使用命令行来手动检查和管理模块。例如,找出当前正在加载哪个模块。以下是输出的示例:
#lsmod
4224 0
18204 2
38920 0
55908 7 ,l2cap,
27532 5
14080 1
isof 36284 0
输出包括:模块名称、大小、使用次数以及依赖它的模块列表。使用计数对于防止当前活动模块被卸载非常重要。 Linux 只允许删除使用量为零的模块。
您可以使用 rmmod 手动加载和卸载模块(还有两个名为 rmmod 的命令行,但它更易于使用,因为它会自动删除模块依赖项)。例如,lsmod 的输出显示我们计算机上有一个名为 isofs 的卸载模块。它的使用计数为零并且没有依赖模块。 (isofs 是一个支持 CD 上使用的 ISO 系统文件格式的模块。)在这种情况下将允许我们卸载该模块:
# -r isofs
现在,isofs 不再出现在 Ismod 的输出中,节省了 36,284 字节的存储空间。如果放入光盘并让它自动安装,则 isofs 模块将自动重新加载,并且 isofs 的使用次数将增加到 1。如果此时尝试删除该模块,则不会起作用,因为它正在使用中:
# -r isofs
致命: isof 正在使用中。
lsmod 仅列出当前加载的模块。它将列出所有可用的模块。它实际上输出了/lib//目录下的所有模块。名单会很长!
事实上,手动加载模块并不常见,但确实可以通过命令行为模块设置参数,例如:
#=1
我们不是在创建模块的参数,而是创建模块的实际参数。
那么您如何知道模块将接受哪些参数呢?更好的方法是使用命令,它列出了有关模块的各种信息。这是模块 snd-hda-intel 的示例
#snd-hda-英特尔
:/lib//2.6.20-16-//声音/pci/hda/snd-hda-intel.ko
:英特尔HDA
:通用公共许可证
: 00C
别名:pci:*sd*bc*sc*i*
别名:pci:*sd*bc*sc*i*
: snd-pcm、snd-页面分配、snd-hda-编解码器、snd
:2.6.20-16-SMP 586
parm:index:Intel HD 音频的索引值。 (整数)
parm: id:Intel HD 音频的 ID。 (夏普)
parm: model:使用给定的板模型。 (夏普)
parm: : 修复 DMA(0 = 自动,1 = 无,2 = , 3 = FIFO 大小)。 (整数)
parm: : 探测 ( = -1)。 (整数)
parm: : 与 with 一起使用(仅用于)。 (布尔)
参数: : (MSI) (int)
参数::布尔
我们对以“parm”开头的部分更感兴趣:它们显示了模块接受的参数。描述很简短,但如果您想了解更多信息,请查看安装源代码,您可以在类似于 /usr/src// 的目录中找到该源代码。
这里面会有一些有趣的事情。例如,文件/usr/src///sound/alsa/ALSA-.txt描述了许多ALSA声音模块识别的参数;文件 /usr/src/ //-.txt 也非常有用。
前几天论坛上有一个关于如何向模块传递参数的示例(详细信息请参见/)。实际上,问题的关键在于 snd-hda-intel 参数需要一些操作才能正确驱动声音硬件,并且在启动时加载时会中止。解决方案的一部分是将 =1 选项分配给模块。如果您手动加载模块,则需要输入:
#snd-hda-英特尔=1
更有可能的是,您在文件 /etc/.conf 中放置了与此类似的行: snd-hda-intel =1
这“告诉”每次加载 snd-hda-intel 模块时都包含 =1 选项。当前的一些 Linux 版本将此信息分离到 /etc/.d 下的不同文件中,而不是将其放在 .conf 中。
/proc 系统文件
Linux 还通过 /proc 系统文件显示许多详细信息。要解释/proc,我们首先需要扩展对文件的理解。除了认为文件是存储在硬盘或CD或存储空间上的持久性信息外,我们还应该将其理解为可以通过传统系统调用(例如:打开、读取、写入、关闭等)访问的任何信息。当然也可以通过普通程序访问。
/proc下的“文件”是一个完全虚拟的部分,给了我们一个视角来看到内部的数据结构。事实上,许多 Linux 报告工具都可以很好地呈现 /proc 下文件中的信息的格式化版本。例如,/proc/ 中的列表将显示当前加载的模块的列表。
同样,/proc/提供了有关虚拟存储系统当前状态的更详细信息,类似的工具以更容易理解的方式提供相同的信息; /proc/net/arp 显示系统 ARP 缓存的当前内容。在命令行中,arp -a 显示相同的信息。
特别有趣的是 /proc/sys 下的“文件”。 /proc/sys/net/ipv4/下的设置告诉我们IP数据包是否会被转发,即是否充当网关。现在,告诉我们这已经关闭了:
# 猫 /proc/sys/net/ipv4/
当您发现可以写入这些文件时,它会变得更加有趣。继续这个例子:
# echo 1 > /proc/sys/net/ipv4/
运行中会开启IP转发(IP)
除了使用 cat 和 echo 检查并更正 /proc/sys 下的设置外,还可以使用以下命令:
#net.ipv4。
网络.ipv4。 = 0
这相当于:
# 猫 /proc/sys/net/ipv4/
也相当于:
# -w net.ipv4.=1
网络.ipv4。 = 1
也相当于:
# echo 1 > /proc/sys/net/ipv4/
需要注意的是,您通过这种方式所做的设置更改只会影响当前正在运行的应用程序,以后将不再有效。如果您希望设置永久有效,请将它们放在 /etc/.conf 文件中。启动时,它在此文件下找到的任何设置都将自动重新确定。
/etc/.conf 下的代码行可能如下所示:net.ipv4.=1
性能调优 ( )
有句话说:/proc/sys下的可写参数催生了整个Linux性能调优亚文化。我个人认为这个说法有点夸张,但是这里有几个你确实想尝试的例子: 10g安装说明(/.htm)要求你设置一组参数,包括: .= 这将共享内存大小设置为2GB。 (公共内存是一种进程内通信机制,允许存储单元在多个进程的地址空间内同时可用)
IBM《 on Linux and 》给出了很多调整/proc/sys下参数的建议,其中包括: vm.=100 该参数控制存储页面如何交换到磁盘。
可以设置一些参数来提高安全性,例如 net.ipv4.=1,它“告诉”不要响应 ICMP 请求,从而使您的网络免受拒绝服务器 (-of-) 攻击,例如 Smurf 攻击。
net.ipv4.conf.all.=1 “告诉”加强入站过滤 ( ) 和出站过滤 ( )
那么是否有一个涵盖所有这些参数的描述呢?好吧,这是行: # -a 它将显示所有参数名称和当前值。这个列表很长,但你无法知道这些参数的作用。另一个有用的参考是《Red Hat Linux 指南》,其中包含完整的章节描述,您可以从中下载。 (王玉蕾译)
扫一扫在手机端查看
-
Tags : linux 内核 原理
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。