1. 程式人生 > >Unix環境高階程式設計閱讀之一——Unix\Linux基礎知識

Unix環境高階程式設計閱讀之一——Unix\Linux基礎知識

所有的作業系統都為它們所執行的程式提供服務。典型的服務包括:執行新程式、開啟檔案、讀檔案、分配儲存區以及獲得當前時間等。 UNIX體系結構示意圖
作業系統是用來控制計算機的硬體資源,提供程式執行環境。 其中,核心的介面被稱為是系統呼叫,公用函式庫構建在系統呼叫之上,應用程式既可以使用公共函式庫,也可以使用系統呼叫。shell是一個特殊的應用程式,它為其他應用程式提供了一個介面。 在目錄/etc/passwd檔案中可以檢視使用者的登入項資訊,在口令檔案中,每個登入項由七個以冒號分隔的欄位組成,分別表示登入名、加密口令、數字使用者ID、數字組ID、註釋欄位、起始目錄以及shell程式。 shell是一個命令列直譯器,它讀取使用者輸入,然後執行命令。
Unix檔案系統 起點是/。 目錄是一個包含目錄項的檔案。每個目錄項都包含一個檔名,同時還包含該檔案屬性的資訊。檔案屬性是指檔案型別、檔案大小、檔案所有者、檔案許可權以及檔案的最後修改時間。 POSIX.1推薦獎檔名限制在以下的字符集之內:字母(a~z,A~Z)、數字(0~9)、句點(.)、短橫線(-)、下劃線(_)。 建立新目錄時,會自動建立兩個目錄“.”和“..”,分別指向當前目錄和父目錄。在最高層次的目錄中,二者含義相同,均指向當前目錄。 dirent.h 是POSIX.1標準定義的unix類目錄操作的標頭檔案,包含了許多UNIX系統服務的函式原型,例如opendir函式、readdir函式.
#include <dirent.h> 是POSIX.1標準定義的unix類目錄操作的標頭檔案,包含了許多UNIX系統服務的函式原型,例如opendir函式、readdir函式. opendir函式: DIR *opendir(const char *pathname);返回值:若成功則返回指標,若出錯則返回NULL。 struct dirent *readdir(DIR *dp); 返回值:若成功則返回指標,若在目錄結尾或出錯則返回NULL。 自己實現的一個簡單的ls工具,程式碼如下: 在Unix中,一般來說,返回0表示執行成功,而1到255表示執行的任務出錯。 Unix中的輸入輸出操作
(1)檔案描述符:一個小的非負整數,核心用以標識一個正在訪問的檔案。 (2)標準輸入重定向、標準輸出重定向、標準錯誤重定向。STDIN_FILENO和STDOUT_FILENO定義在<unistd.h>中,它們指定了標準輸入和標準輸出的兩個檔案描述符。在POSIX標準中,它們分別是0和1。 (3)不帶緩衝的IO:函式open、read、write、lseek以及close提供了不帶緩衝的I/O。這些函式都使用檔案描述符。 read函式返回讀取的位元組數。當檔案到達尾端時,read返回0;當發生讀取錯誤,read返回-1。注意,Unix的系統函數出錯時,大多返回-1。 (4)標準輸入輸出函式:標準輸入輸出函式為那些不帶緩衝的輸入輸出函式提供了一個帶緩衝的介面。無須擔心最佳的緩衝區大小的選擇,並且簡化了對輸入行的處理。如:getc、putc、fgets函式、printf函式。標頭檔案<stdio.h>。 Unix的程式與程序 程式是一個儲存在磁碟上某個目錄中的可執行檔案。核心使用exec(七個函式中的一個),將程式讀入記憶體,並執行程式。使用getpid這個函式可以獲取當前執行的程序的id號,它返回的是一個pid_t型別的資料,可以將其強制轉換為long型別。 有關於程序控制的函式:fork、exec、waitpid。 ①其中exec有七個變體。 ②fork函式對父程序返回子程序的pid(一個非負整數),對子程序返回0。所以說,fork被呼叫一次,但是返回兩次(父與子)。 ③waitpid函式可以指定要等待的程序id。它將返回子程序的終止狀態(status變數)。 ctrl+D是一個控制字元,表示預設的檔案結束符。 Unix的執行緒和執行緒ID 一個程序內的所有執行緒共享同一地址空間、檔案描述符、棧以及與程序相關的屬性。因為它們能訪問同一儲存區,所以在個執行緒訪問共享資料時,需採取同步措施。執行緒也有ID,但僅在本程序內有用。 Unix的出錯資訊 出錯通常會返回一個負值。errno這個整型變數被設定為具有特定資訊的值。有大約15種。<errno.h>重定義。 在Unix手冊intro(2)中也列出了所有這些出錯的常量。在Linux種,定義在errno(3)手冊中。使用man 3 errno命令可以檢視。 POSIX和ISO C將errno定義為一個符號,它擴充套件成為一個可修改的整型左值。 對於errno需要注意的是,(1)如果沒有出錯,該值不會被清除;僅當函式返回值指明出錯時,才檢驗其值;(2)沒有任何函式將errno設定為0,<errno.h>重所定義的所有常量都不為0。 C標準中定義了兩個函式用於打印出錯資訊。 (1)<string.h>中,char *strerror(int errnum);它將errnum對映為一個出錯字串,並返回其指標。 (2)<stdio.h>中,void perror(const char *msg);perror對應當前的errno,輸出一條出錯資訊。首先輸出msg指定的字串,然後輸出一個冒號,之後就是出錯資訊。 出錯分類: (1)致命性出錯:無法執行恢復動作,最多就是想螢幕打印出一條出錯資訊或者將一條出錯資訊寫入日誌檔案中。 (2)非致命性出錯:EAGAIN(資源暫時不可用)、ENFILE(系統當前開啟過多檔案)、ENOBUFS(沒有緩衝區)、ENOLCK(沒有鎖)、ENOSPC(裝置中空間不足)、EWOULDBLOCK(操作將被阻塞),有時,ENOMEM(空間不足)也是非致命性出錯。當EBUSY(裝置或資源正忙)指明共享資源正在使用時,也可以將其作為一個非致命性的出錯處理。當EINTR(中斷函式呼叫)中斷一個慢速系統呼叫時,可將它作為非致命性出錯處理。 對於非致命性出錯的典型恢復操作是延遲一段時間,然後重試。 Unix使用者標識 (1)使用者ID。ID為0的使用者是根使用者或稱是超級使用者。使用<unistd.h>中的getuid函式可以獲取使用者id。 (2)組ID。/etc/group檔案中將組名應設為數值的組ID。這種機制允許同組的各個成員之間共享資源。使用<unistd.h>中的getgid函式可以獲取組id。 (3)附屬組ID。允許一個使用者屬於多至16個其他的組。 Unix訊號 用於通知程序發生了某種情況。例如,SIGFPE是浮點異常,當除數為零的時候會被髮送。 Unix程序有三種處理訊號的方式: (1)忽略訊號。 (2)按系統預設方式處理。 (3)提供一個函式,當訊號發生時,呼叫這個函式。這被稱為捕捉訊號。 終端鍵盤有兩種產生訊號的方法:中斷鍵(ctrl+C或Delete鍵)和退出鍵(ctrl+\鍵)。還有一種方式,呼叫kill函式,要求是程序的所有者或是root使用者。 為了捕捉訊號,程式需要呼叫signal函式。 Unix時間值 Unix系統使用兩種不同的時間值: (1)日曆時間。系統基本型別time_t用來儲存這個時間值。 (2)程序時間。系統基本型別clock_t用來儲存這個時間值。使用sysconf這個函式獲取時鐘嘀嗒。 Unix為一個程序維護了3個程序的時間值: ①時鐘時間,程序執行的時間總量,其值與系統中同時執行的程序數有關。 ②使用者CPU時間:執行使用者指令所用的時間量。 ③系統CPU時間:為該程序執行核心程式所需的時間量。 系統呼叫和庫函式 系統呼叫時作業系統提供的多種服務的入口點,由此程式向核心請求服務。 Unix所使用的技術是為每個系統呼叫在標準C庫中設定一個具有同樣名字的函式。使用者程序用標準C呼叫序列來呼叫這些函式,然後,函式又用系統所要求的技術呼叫相應的核心服務。 注意區分系統呼叫和庫函式 (1)系統呼叫和庫函式從實現者的角度來看,具有根本的區別。但從使用者角度,其區別並不重要。有些庫函式可能會呼叫一個或多個系統呼叫,但他們並不是核心的入口點。有些庫函式並不使用任何核心的系統呼叫。 舉例:malloc庫函式是以特定方式進行儲存空間分配的函式。它在根本上,其實是呼叫了系統呼叫sbrk,這個系統呼叫是按指定位元組數增加或減少程序的地址空間。兩者的職責不同,核心中的系統呼叫分配一個空間給程序,而庫函式malloc砸在使用者層次上管理這個空間。 (2)系統呼叫通常提供一種最小介面,而庫函式通常提供比較複雜的功能。