系统调用
为什么用户程序不能直接访问内核提供的服务?
在Linux中,为了更好地保护内核空间,程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。
是不是系统调用或库函数一定会执行成功?怎么知道执行成功或失败?执行失败了怎么办?
几乎所有的系统调用或库函数都会返回某种类型的状态值,以表明是否执行成功!
需要对状态值进行检查!!
需要对执行失败的情况进行处理,至少也要显示错误信息!!!
操作系统提供的服务
- 进程控制
- 文件系统控制
- 内存管理
- 网络管理
- 用户管理
- 进程间通信
- …
Linux文件的基本概念
文件的概念
- “文件”这个名词不陌生,什么是文件?
- 系统资源(内存、硬盘、一般设备、进程间通信的通道等)的一个抽象
- 对系统资源进行访问的一个通用接口。
采用这种“文件”的方式有什么好处?
对资源提供通用的操作接口,可以极大地简化系统编程接口的设计。既然文件是一个通用的接口,由于系统资源多种多样,是不是意味着文件类型也多种多样?
文件的类型
常见的文件类型(可以通过文件来访问的系统资源)有:
- 普通文件
一般意义上的文件,作为数据存储在磁盘中,可以随机访问文件的内容。Linux系统中的文件是面向字节的,文件的内容以字节为单位进行存储和访问。 - 目录
目录是一种特殊的文件,目录可以像普通文件一样打开、关闭以及进行相应的操作。 - 管道
管道是Linux中的一种进程间通信的机制。 - 设备文件
设备文件没有具体的内容,对设备文件的读写操作实际上与某个设备的输入输出操作关联在一起。 - 符号链接
符号链接的内容是指向另一个文件的路径。当对符号链接进行操作时,系统会根据情况将这个操作转移到它所指向的文件上去,而不是对它本身进行操作。 - socket
socket也是一种进程间通信的方式,与管道不同的是,它们可以在不同的主机上进行通信,也就是网络通信。
文件描述符
- 所有执行I/O操作的系统调用使用文件描述符来表示打开的文件。
- 文件描述符是一个非负整数。
- 文件描述符可以表示各种类型的打开的文件。
- 对文件的操作只要使用文件描述符即可指定所操作的文件。
文件操作的系统调用
文件操作的一般过程
- 打开文件,打开成功后,应用程序将获得文件描述符。
- 应用程序使用文件描述符对文件进行读写等操作。
- 全部操作完毕后,应用程序需要将文件关闭以释放用于管理打开文件的内存。
Opening a File: open()
open()系统调用可以打开或创建一个文件。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
Returns file descriptor on success, or –1 on error
各参数及返回值的含义如下:
- pathname:要打开或创建的文件名称。
- flags:标志位,指定打开文件的操作方式。
- mode:指定新文件的访问权限。(仅当创建新文件时才使用该参数)
返回值:若成功返回文件描述符,否则返回-1并设置变量errno的值。
基本取值:
- O_RDONLY:以只读方式打开文件。
- O_WRONLY:以只写方式打开文件。
- O_RDWR:以读写方式打开文件。
注意:上述三个常量必须指定且只能指定一个。
- 可选取值(部分):
- O_CREAT:如果被打开的文件不存在,则自动创建这个文件。
- O_EXCL:如果O_CREAT标志已经使用,那么当由pathname参数指定的文件已经存在时,open返回失败。
- O_TRUNC:如果被打开的文件存在并且是以可写的方式打开的,则清空文件原有的内容。
- O_APPEND:新写入的内容将被附加在文件原来的内容之后,即打开后文件的读写位置被置于文件尾。
Reading from a File: read()
read()系统调用从打开的文件中读取数据。
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
Returns number of bytes read, 0 on EOF, or –1 on error
各参数及返回值的含义如下:
- fd:要读取的文件的描述符。
- buf:读取到的数据要放入的缓冲区。
- count:要读取的字节数。
- 返回值:若成功返回读到的字节数,若已到文件结尾则返回0,若出错则返回-1并设置变量errno的值。
注意:
- 这里的size_t是无符号整型,ssize_t是有符号整型。
- buf指向的内存空间必须事先分配好。
使用read()时,可能遇到哪些情况?
- 返回值等于count
- 返回一个大于0小于count的值
- 返回0
- 阻塞
- 返回-1且errno的值为EINTR
- 返回-1且errno的值为EAGAIN
- …
Writing to a File: write()
write()系统调用向打开的文件写数据。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
Returns number of bytes written, or –1 on error
各参数及返回值的含义如下:
- fd:要写入的文件的描述符。
- buf:要写入的数据所存放的缓冲区。
- count:要写入的字节数。
- 返回值:若成功返回已写的字节数,出错则返回-1并设置变量errno的值。
使用write()时,可能遇到哪些情况?
- 返回值等于count
- 返回一个大于0小于count的值
- 阻塞
- 返回-1且errno的值为EINTR
- 返回-1且errno的值为EAGAIN
- 返回-1且errno的值为EBADF
- 返回-1且errno的值为EFAULT
- 返回-1且errno的值为EPIPE
- …