当前位置:首页>Linux>Linux内核是如何对外提供服务的?

Linux内核是如何对外提供服务的?

  • 2026-10-10 17:01:47
Linux内核是如何对外提供服务的?

为什么需要Linux内核?

早期处理器(如8086、80286、80386)能力较弱,通常只能运行一个单循环程序来处理所有任务。那时从汇编语言升级到 C 语言编程已属不易,任务简单,即便整体崩溃影响也有限。

随着处理器能力增强,系统可同时运行多个任务,且这些任务的归属方往往不同。若任务A 影响了任务 B,问题定位困难,互相推诿成为常态。操作系统因此诞生,核心目标之一就是隔离与管理任务。

处理器的指令集逐步分化为不同特权级别(x86:Ring 0~3;ARM:EL0~EL3;RISC-V:U/S/M)。指令总体上可分为两类:

• 普通指令:无特殊权限,无法访问关键硬件资源

• 特权指令:可操作中断控制器、MMU 页表等,直接影响系统稳定性

操作系统的内核是唯一被允许执行特权指令的软件实体。

用户态任务通过系统调用进入内核,彼此之间只能通过进程间通信(IPC)交互,无法直接破坏内核或其他进程。这是现代操作系统设计的核心隔离理念。

所以大体的一个Linux系统是下图这样,最下面是硬件,包括处理器和各种外围设备,硬件上面是Linux内核和内核态的各种驱动和内核模块,再上面就是各种各样的进程,呈现各种不同的用户界面,但是都是在用户态运行。

Linux内核主要功能

下图展示了Linux内核的一些主要功能模块,不是全部。

从下图也可以更清楚地看到Linux宏内核的特征,绿色的进程管理和内存管理应该是一个操作系统内核的核心,黄色的这些模块(如文件系统、网络协议栈等)在微内核架构中通常作为用户态服务实现,而 Linux 作为宏内核,将它们全部集成在内核态,因此被称为宏内核。

这些内核模块没有上下层级的概念,都属于一个层次,彼此可以互相调用。

各模块简要说明:

  • 内存管理:基于MMU 实现进程地址空间隔离,是进程隔离的硬件基础

  • 存储系统:Block 层位于上层文件系统与底层设备驱动之间,向上提供统一接口,向下通过不同驱动(如 SCSI、NVMe)适配各类硬件。

  • 文件系统:文件系统通常构建于块设备之上,但也有基于内存(tmpfs)、网络(NFS)或特殊设备(proc、sysfs)的文件系统,支持ext4、XFS、NFS、tmpfs 等,通过 VFS 提供统一接口,Linux支持了很多种类的文件系统,这些文件系统统一通过虚拟文件系统VFS进行了抽象,这样上面的进程程序编写代码时,不需要关心具体是哪个文件系统(比如ext4、NTFS等),读写接口都是统一的。

  • 网络系统:管理网络设备,实现TCP/IP 协议栈,提供 Socket 系统调用。TCP/IP 协议栈具有极高的网络兼容性要求,因此 Linux 内核长期维护并优化其 TCP/IP 实现,难以用其他协议栈替代。

  • 加密模块:内核Crypto API,支持对称/非对称加密、哈希等,广泛用于 IPsec、dm-crypt 等。

  • 设备驱动:字符设备、块设备、网络设备等的驱动程序,Linux 内核主线已包含大量通用设备驱动,芯片厂商通常以内核模块形式提供板级支持包(BSP)或通过 upstream 方式提交驱动代码;

基本上Linux内核覆盖了当前IT领域的各种基础需求,用户只需要针对性开发自己特有的部分,避免了相同功能的重复开发,我们都需要感谢Linux。

Linux内核是如何对外提供服务的?

Linux内核通过系统调用接口(System Call Interface)对上面的用户态程序提供支持。

但是我们实际编程的时候,很少会直接使用系统调用接口,那是因为glibc库已经基于系统调用接口封装好了更容易调用的glibc提供的库函数api。

下图展示了如果我们新开发一个C语言程序,一般有3种函数调用的方式:

  • Linux内核提供的系统调用,这个调用一般不推荐使用

  • Glibc提供的api,这是最常用的方式,符合POSIX接口标准,glibc(GNU C Library) 是 GNU 项目提供的 C 标准库 + POSIX 接口的主流实现,glibc就是上一篇提到的GNU的项目输出,glibc会进行系统调用)

  • 其他软件也可以做成类似glibc的库,提供api供其他程序调用

还有一种方式,图中的4,程序之间通过进程间通信或网络通讯等方式进行交互。

总结一下这4种方式:

1.直接系统调用(不推荐,需处理架构差异与 errno)

2. glibc 封装 API(最常用,符合 POSIX 标准)

3. 其他第三方库(如 libuv、libevent)

4. 进程间通信/网络通信(不经过内核接口,但依赖内核IPC 机制)

通常的C语言编程,推荐使用glibc,而不是Linux系统调用,可以看一下千问总结的二者的区别

顺便提一下POSIX标准

POSIX = Portable Operating System Interface + X

(可移植操作系统接口)(表示Unix传统)

POSIX是由IEEE主导制定,得到ISO国际认可,并由多组织共同维护的开放系统接口标准。它的诞生解决了Unix分裂带来的兼容性问题,如今已成为跨平台系统编程的事实标准。当你使用Linux的write()、fork()、open()等接口时,你正在使用的正是这个30多年前确立的标准。

同时也了解一下,Linux下,除了glibc之外,也有其他的常用库可以选择。

举例说明:一个写磁盘操作的过程

假设要写几个字符(字节)到一个已经打开的文件中,那么在用户态程序(软件)编程的主要过程是这样的:

用户态执行路径:

1,调用glibc的write函数:ssize_t ret = write(fd, buffer, size);

2,Glibc 内部调用 syscall() 函数:ssize_t ret = syscall(SYS_write, fd, buffer, size);

------ 用户态 ↔ 内核态切换点 ------

内核态执行路径:

3. 系统调用入口 → sys_write()

4. VFS 层 → vfs_write(),定位具体文件系统;文件是属于文件系统的,Linux实现了一个虚拟文件系统VFS,所以在Linux内核情况下,sys_write会先调用到vfs的write

5. 文件系统层(如 ext4)→ ext4_file_write_iter(),从VFS再定向到特定的文件系统比如ext4对应的write操作;

6. 块设备层(Block Layer)→ 提交 I/O 请求到块设备队列;文件系统是构建在块设备block上的,所以write操作最终会调用到块设备block层的write操作;

7. 设备驱动层(如 SCSI 驱动 sd)→ 与硬件控制器交互;块设备block的write操作又会根据块设备具体的驱动,比如磁盘挂载的SCSI 控制器(SAS、SATA等)的驱动,调用到对应驱动的一系列操作,最终完成写入文件对应的最终磁盘上;

8. 硬件控制器(SAS / SATA / NVMe)→ 与磁盘固件通信,完成物理写入

然后逐级返回,支持同步/异步完成通知。

【说明】

• 磁盘固件与控制器之间的协议交互不属于 Linux 内核,内核只负责驱动侧实现

• 本例假设文件已打开;若未打开,需先调用 open(),并可能需要 lseek() 定位写入位置

Docker容器在用户态

现在AI Agent使用较多的docker容器,功能比较强大,但其实也是在用户态的。但容器的隔离与资源限制完全由内核提供,因此“容器在用户态”是指进程执行级别,而非容器实现不依赖内核

一个Docker 容器本质上是由 Namespaces 提供隔离、Cgroups 提供资源限制的一组普通 Linux 进程。

这些进程仍然运行在用户态,但被内核“隔离”和“限制”了。

容器内的应用代码(比如你的Python 或 Nginx)和宿主机上的普通用户程序一样,运行在 CPU 的用户态(如 x86 的 Ring 3,ARM64 的 EL0)。

下面是千问总结的Docker信息:

顺便对比一下容器与虚拟机的区别:

最新文章

随机文章