系统调用(系统API)
什么是系统调用
-
由操作系统向应用程序提供的程序接口信息,本质上就是应用程序与操作系统之间交互的接口。
-
操作系统的主要功能是为了管理硬件资源和为应用软件的开发人员提供一个良好的环境,使得应用程序具有更好的兼容性,为了达到这个目的,内核提供一套统一的具有一定功能的内核接口函数,称为系统调用\系统函数,以C语言函数的格式提供给用户
-
操作系统负责把应用程序的请求传给内核,由内核调用具体内核功能完成所需请求,结束后把结果通过操作系统的接口函数的返回值传递给调用者
-
UNIX\Linux大部分系统中的系统功能都是通过系统调用来实现的,相当于调用系统函数,但是它们不是真正意义的函数,当调用它们时,进程立即进入内核态,当调用结束,会重新转入回用户态
time ./<可执行文件名> # 统计该进程的时间分布
real 0m0.003s # 总时间
user 0m0.001s # 用户态执行时间
sys 0m0.000s # 内核态执行之间
总时间 = 用户态 + 内核态 + 用户态\内核态切换耗时 + 休眠时间
strace ./可执行文件名 # 追踪函数的底层调用过程,以此了解标准库函数中用了哪些系统调用
普通函数与系统函数(系统调用)的区别:
普通函数的调用步骤:
-
调用者会把要传递的参数压入栈内存
-
根据函数名也就是该函数的代码段地址,跳转到该函数代码段中执行
-
从栈内存中弹出传递的参数数据
-
定义的相关局部变量会入栈到该函数的栈内存进行扩展,并执行相关代码
-
返回执行结果
-
销毁该函数的栈内存
-
返回调用语句处继续执行
系统函数的调用过程:
-
当执行到系统函数的位置时,会触发软件中断机制
-
然后进程会转入内核态执行,由内核负责把参数从用户空间拷贝到内核空间
-
然后内核根据中断编号来执行相应的操作
-
等执行完毕后,内核再把执行结果从内核空间再拷贝回用户空间中
-
返回到中断触发位置,转换回用户态继续执行进程
一切皆文件
-
在UNIX\Linux系统中,操作系统把所有服务、设备都抽象成了文件,因为这样可以给各种设备、服务提供同一套统一而简单的操作接口,程序就可以像访问普通文件一样,控制串口、网络、打印机等设备
-
因此在UNIX\Linux系统中对文件就具有特别重要的意义,一切皆文件,所以大多数情况下,只需要五个基本系统函数操作 open/close/read/write/ioctl,既可以完成对各种设备的输入、输出控制
文件分类:
-
普通文件 - 包括文本文件、二进制文件、各种压缩包文件等
-
目录文件 d 类似Windows的文件夹
-
块设备文件 b 用于保存大块数据的设备,例如磁盘
-
字符设备文件 c 用于对字符处理的服务、设备,例如 键盘
-
链接文件 l 类似于Windows的快捷方式
-
管道文件 p 用于早期进程通信
-
Socket文件\套接字文件 s 用于网络通信
文件描述符
什么是文件描述符:
-
文件描述符是一种非负的整数,用于表示一个打开了的文件
-
由系统调用(open\creat)返回值,在后续操作文件时可以被内核空间引用去操作对应的文件
-
它代表了一个内核对象(类似于FILE*),因为内核不能暴露它的内存地址,因此不能返回真正的文件地址给用户
-
内核中有一张表格,记录了所有被打开的文件对象,文件描述符就是访问这张表格的下标,文件描述符也叫做句柄,是用户操作文件的凭证
-
内核只要启动,一定会给每个进程打开三个文件描述符,并且是一直默认打开,除非自己手动关闭
// 在<unistd.h> 定义了三个宏
#define STDIN_FILENO 0 // 标准输入 文件指针 stdin
#define STDOUT_FILENO 1 // 标准输出 文件指针 stdout
#define STDERR_FILENO 2 /* 标准输入 文件指针 stderr
文件描述符与文件指针:
-
在Linux系统中打开文件后,内存中(内核区间)就会有一个内核对象,也就是记录了该文件相关信息的结构变量,但是内核为了自己的安全不能把它的地址返回给用户,而且内核区间用户是无法直接访问的,就算返回也无权限访问。
-
而且一个进程可以同时打开多份文件,所以操作系统会在内核区间创造一份索引表,表中的每一项都指向了一个打开的文件内核对象,而用户拿到的文件描述符就是该索引表的下标(主键),因此不同进程之间直接交互文件描述符是没有意义的。
-
C语言标准函数中,使用文件指针代表文件,文件指针指向的区间是进程的用户 区间的一个结构变量(文件结构变量FILE类型),里面记录了该文件的文件描述符还有一些文件缓冲区,因此某种程度上可以理解文件指针就是文件描述符,只是不同的形式,给不同的对象使用而已
int fileno(FILE *stream);
功能:把文件指针转换成文件描述符
FILE *fdopen(int fd, const char *mode);
功能:把文件描述符转换成文件指针