系統調用
爲什麼用戶程序不能直接訪問內核提供的服務?
在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
- …