**《UNIX環境高級編程》(第二版)(人民郵電出版社)**
**【美】W.Richard Stevens& Stephen A.Rago 著**
本書的主要結構分為以下幾個部分:
(1).**第1章UNIX基礎知識**
①UNIX體系結構中,最主要的是內核,它有一些稱為系統調用的接口與外界交互。在內核之上有shell 和庫函數,然后是應用軟件。
②常見的shell有Bourneshell(sh), Bourne_again shell(bash), C shell(csh), Korn shell(ksh), TENEX Cshell(tcsh)。
③不能出現在文件名中的字符只有斜線(/)和空操作符(null)兩個。
④文件描述符(file descriptor)通常是一個小的非負整數。
⑤當一個進程收到一個信號時,有三種選擇:忽略該信號;按系統默認方式處理;提供一個函數,信號發生時調用這個函數。
**(2)?第1章UNIX標準及其實現**
1、本章介紹了三個主要標準:ISO C、POSIX和SingleUNIX Specification 。POSIX標準中的都只是接口,而不是實現,所以不區分系統調用和庫函數,都稱為函數。Single UNIX Specification(單一UNIX規范)是POSIX.1標準的一個超集,定義了一些附加的接口。
2、提高移植性的限制有兩類:編譯時限制和運行時限制。ISO C定義的限制都是編譯時限制,列在頭文件<limits.h>中。POSIX.1定義的限制和常量有5類:①不變的最小值;②不變值;③運行時可以增加的值;運行時不變的值(可能不確定);⑤路徑名可變值(可能不確定)。
3、如果在編譯一個程序時,希望它只使用POSIX的定義而不使用任何其他的定義,就需要定義常量_POSIX_C_SOURCE。
**(3)文件I/O**
1、UNIX系統中的大多數文件I/O只需用到5個函數:open、read、write、lseek以及close。由于新的open函數提供了O_CREAT和O_TRUNC選項,也就可以完全替代creat函數了。Lseek函數的作用就是為一個打開的文件設置其當前文件偏移量,定位讀寫的位置。
2、內核使用三種數據結構表示打開的文件:進程表中的一個記錄項、文件表、v節點(在Linux中由通用型的i節點來實現)。
3、使用pread和pwrite函數可以實現原子讀寫。Dup和dup2函數可以復制一個現存的文件描述符。Sync、fsync和fdatasync函數可以使放在緩存中的數據寫入磁盤,免得系統崩潰時造成數據丟失。Fcntl函數可以改變已打開文件的性質。
**(4)文件和目錄**
1、本章討論的中心是3個stat函數以及它們返回的信息。Stat函數返回文件的信息結構,fstat函數獲取描述符為filedes的文件的有關信息,lstat可以返回符號鏈接的有關信息而不是它所指向的文件的有關信息。
2、其他函數:access函數按實際用戶ID和實際組ID進行訪問權限測試;umask函數為進程設置文件模式創建屏蔽字;chmod和fchmod函數用于更改現有文件的訪問權限;chown、fchown和lchown函數用于更改文件的用戶ID和組ID;truncate和ftruncate函數把現有文件截短為參數length字節;link、unlink創建和刪除一個指向現有文件的鏈接(硬鏈接);symlink函數創建一個符號鏈接;utime函數可以更改一個文件的訪問和修改時間;chdir、fchdir函數可以更改當前工作目錄;getcwd返回工作目錄的絕對路徑。
**(5) 標準I/O庫**
1、在UNIX系統中,標準I/O庫最終都要調用第3章中說明的I/O例程。
2、當用標準I/O庫打開或創建一個一個文件時,我們已使一個流與一個文件相關聯。每個標準I/O流都有一個與其相關聯的文件描述符,可以對一個流調用fileno函數以獲取其描述符。
3、對一個進程預定義了3個流:標準輸入、標準輸出和標準出錯。
4、打開標準I/O流的函數:fopen、freopen、fdopen。用fclose函數關閉。
5、流的讀寫函數:getc、putc,fgetc、fputc,getchar、putchar,fgets、fputs,gets、puts(這一對不推薦使用)。
6、格式化輸入輸出函數:printf、scanf,fprintf、fscanf,sprintf、snprintf、sscanf。
7、使用tmpnam和tmpfile函數可以創建臨時文件。
**(6 )系統數據文件和信息**
1、一般情況下,對于每個數據文件至少有三個函數:get函數,讀出記錄;set函數,打開文件然后反繞它;end函數,關閉文件。
2、與用戶ID相關的幾個重要的文件是:口令文件(passwd);陰影口令文件(shadow);組文件(group);utmp文件,記錄當前登錄進系統的各個用戶;wtmp文件,跟蹤各個登錄和注銷事件。
3、關于時間和日期的一個函數。Time函數返回當前時間:自1970年1月1日零時以來的秒數,而且是國際標準時間。Gettimeofday函數與time類似,只是可以提供更高的分辨率(微秒)。Localtime和gmtime函數將日歷時間轉換成以年、月、日、時、分、秒周日表示的時間,填充structtm結構。而mktime函數則相反,轉換成time_t值,也就是日歷時間。Asctime和ctime函數產生26字節的字符串,表示年月日時分秒等信息。Strftime函數提供格式化的時間表示,類似于printf[**程環境**??f-?L?Ntuation']()
[**]()**
**(7 ) 進程環境**
1、進程的正常終止大多是調用exit函數,它先調用各終止處理程序(由atexit函數登記),然后按需多次調用fclose關閉打開的所有流。
2、一個C程序的組成部分:正文段(指令)、初始化數據段、非初始化數據段(bss)、棧(函數調用時使用)、堆(動態存儲分配)。
3、存儲空間的動態分配函數有3個:malloc、calloc、realloc。而free函數釋放存儲空間。
4、系統中的環境變量由各個應用程序解釋使用,內核不過問。相關的3個函數,putenv添加一個環境變量、setenv更改一個環境變量、unsetenv刪除一個環境變量。
5、在C中,goto語句是不能跨越函數的,而執行這類跳轉功能的是函數setjmp和longjmp 。
6、使用getrlimit和setrlimit函數查詢和修改系統對一個進程的資源限制。
**(8 ) 進程控制**
1、每一個進程都有一個非負整型表示的唯一進程ID。這是最重要的一個進程標識符。
2、本章的重點fork。一個現有進程可以調用fork函數創建一個新進程。有兩種用法:一個父進程希望復制自己,使父、子進程同時執行不同的代碼段;一個進程想啟動一個完全不一樣的進程(例如利用shell執行命令)。Fork調用一次返回兩次,在子進程中返回0,在父進程中返回子進程的ID。
3、vfork用于創建一個新進程,但其目的是exec一個新程序。就像fork的第二種用法。但是vfork保證子進程先運行。而對于fork,子進程還是父進程先運行是不確定的。
4、對于一個進程的任意一種終止情形,我們都希望被終止的進程能夠通知其父進程它是如何終止的。終止函數exit、_exit和_Exit把進程的退出狀態作為參數傳遞給函數。
5、調用wait和waitpid函數可以等待子進程終止的異步信號的通知。但是一個子進程終止之前,wait使其調用者阻塞,而waitpid有一個選項,可使調用者不阻塞。
6、exec函數族。調用exec函數不創建新的進程,前后進程ID并不改變,它只是用一個全新的程序替換了當前進程的正文、數據、堆和棧。一共有6個函數:execl、execv、execle、execve、execlp和execvp。Exec函數的一種變體:解釋器文件。Shell腳本是其中比較常見的一種。
**(9) 進程關系**
1、本章最重要的是三個概念:進程組、會話和作業控制。進程組是一個或多個進程的集合,擁有一個唯一的ID,有一個組長進程。進程可以通過調用setpgid來加入一個現有的組或者創建一個新進程組。而會話是一個或多個進程組的集合,進程調用setsid函數建立一個新會話。作業控制允許在一個終端上啟動多個作業(進程組),它控制哪一個作業可以訪問終端,哪些作業在后臺運行。
**(10)信號**
1、這一章是相當重要的一章,用了50多頁來講解。含有大量的實例程序,講解得比較深入。
2、信號是軟件中斷,用于處理異步事件。每一個信號都有一個名字,而且都以三個字符SIG開頭,對應一個整型編號。信號產生的情況:①用戶按下某些終端按鍵;②硬件異常;③調用kill函數發送;④用戶使用kill命令發送;⑤檢測到某種軟件條件已經發生。三種信號處理方法:①忽略它;②捕捉它,然后調用特定的用戶函數;③執行系統默認動作。
3、一些與信號有關的重要的函數。Signal函數用于設置某信號的處理程序,在很多平臺該函數都是由sigaction函數來實現的。Kill函數將信號發送給進程或進程組。Alarm函數設置過一段時間后發送信號給自己,而pause函數使自己掛起直到捕捉到一個信號。Sigprocmask函數可以檢測或更改其信號屏蔽字。Sigpending函數返回對應進程是阻塞的信號集。Sigsuspend函數解除一個阻塞信號并且馬上使進程休眠,兩步是一個原子操作。Abort函數用于使異常程序終止,進程接收到信號后終止之前可以執行一些必須的清理工作。
**(11)線程**
1、這一章有三部分的內容,線程的概念、線程的創建和終止、線程的同步。
2、多線程設計的好處:①使得處理異步事件的代碼變得簡化。②共享方便。③提高整個程序的吞吐量。④改善交互程序的響應時間。
3、線程包含了表示進程內執行環境必需的信息,包括線程ID(只在它所屬的進程環境中有效)、一組寄存器值、棧、調度優先級和策略、信號屏蔽字、errno變量以及線程私有數據。
4、線程的創建使用pthread_create函數。但是創建后不保證哪一個線程先運行。如果進程中的任一線程調用了exit、_Exit或者_exit,那么整個進程就會終止。而單個線程有三種方式推出:①從啟動例程中返回。②被同一進程中的其他線程取消。③自己調用pthread_exit函數。
5、實現線程同步主要有三種方式:使用互斥量、使用讀寫鎖、使用條件變量。
**(12) 線程控制**
1、線程屬性存放于數據結構pthread_attr_r中。可以使用函數pthread_attr_init函數來初始化這個數據結構,使用pthread_attr_destroy函數來用無效數值填充,即“反初始化”。使用函數pthread_attr_setdetachstate函數修改結構中的detachstate屬性,可以讓線程以分離狀態啟動。線程的棧屬性通過pthread_attr_setstack函數來設置。
2、線程的同步屬性包括互斥量屬性、讀寫鎖屬性、條件變量屬性。它們都有對應的進出共享屬性,存在于不同的數據結構中。
3、如果一個函數在同一時刻可以被多個線程安全地調用,就稱該函數是線程安全的。如果函數對異步信號處理程序的重入是安全的,那么就說函數是異步-信號安全的。
4、另外是線程屬性還有可取消狀態和可取消類型。這兩個屬性影響著線程在響應pthread_cancle函數調用時所呈現的行為。
**(13)守護進程**
1、守護進程也稱精靈進程(daemon)。
2、守護進程編程規則:①調用umask將文件模式創建屏蔽字設置為0。②調用fork,然后使父進程退出。③調用setsid以創建一個新會話。④將當前工作目錄更改為根目錄。⑤關閉不再需要的文件描述符。
3、守護進程沒有控制終端,它的出錯信息通過syslog設施來記錄。對應的函數有openlog、syslog、closelog、setlogmask。
**(14) 高級I/O**
1、非阻塞I/O使得當我們使用open、read、write這樣的操作時,如果不能完成則立即出錯返回,不會阻塞。
2、記錄鎖對一個文件區域進行加鎖,當一個進程正在對一個文件的某區域進行操作時可以阻止被另外一個進程對其的操作而引起的混亂。注意,這不是對整個文件加鎖,只是一個文件的指定區域,所以這個鎖也叫字節范圍鎖。
3、當一個進程需要請求多個描述符時,可以使用I/O多路轉接技術來處理。大致是先構造一張有關描述符的表,然后調用一個函數,直到這些描述符中的一個準備好進行I/O時,該函數才返回。可以選擇的函數有三個:poll、pselect和select。
4、高級I/O還提供了一些很有用的擴展函數。Readv和writev函數實現在一次函數調用中讀、寫多個非連續區域。Readn和writen函數可以指定讀、寫N個字節的數據,能夠自動處理返回值小于要求值的情況,是多次調用read和write函數實現的。
**(15) 進程間通信**
1、最古老的IPC是管道,它有兩方面的局限性:半雙工傳輸(有個別系統實現了全雙工);只能在有公共祖先的進程間使用。一些相關函數:pipe函數用于創建一個新管道,popen函數實現創建一個管道然后調用fork產生一個子進程,然后使用管道與其通信。
2、當一個程序產生某個過濾程序的輸入,同時又讀取該過濾程序的輸出時,則該過濾程序就稱為協同進程。
3、FIFO有時被稱為命名管道。一些相關函數:mkfifo用于創建,使用open函數打開。
4、有三種IPC統稱為XSI IPC,分別是消息隊列、信號量(其實它真正上是一種同步原語)、共享存儲器。每一個XSI IPC結構都有對應的一個非負整型標識符和一個鍵。三種的創建函數分別為msgget、semget、shmget。
**(16 )網絡IPC:套接字**
1、套接字是通信端點的抽象,訪問套接字要用套接字描述符。創建一個套接字使用socket函數。使用函數shutdown可以禁用一個套接字,通過參數決定關閉寫端或者讀端。
2、套接字使用的地址有一個通用的結構:socketaddr結構。使用函數bind可以將地址綁定到一個套接字,而調用函數getsocketname查看綁定到一個套接字的地址。
3、使用函數connect建立一個連接。對于服務器,可以調用listen函數來宣告可以接受連接請求,然后使用函數accept函數獲得連接請求并建立連接。
4、六個數據傳送相關的函數。Send和sendto函數很相似,都是把數據發出去,只是sendto允許在無連接的套接字上指定一個目標地址。而,sendmsg函數可以指定多重緩沖區傳輸數據,類似于writev函數。Recv函數用來接收數據,recvfrom函數比recv多一個功能是可以得到數據發送者的地址。對應于sendmsg,有recvmsg函數。
**(17 ) 高級進程間通信**
1、基于STREAMS的管道(簡稱STRREAMS管道,STREAMS pipe)是一個雙向(全雙工)管道。可以用fattach函數給STREAMS管道一個文件系統中的名字,使用fdetach函數撤銷它。
2、UNIX域套接字用于在同一臺機器上運行的進程之間的通信。提供流和數據報兩種接口。使用socketpair函數可以創建一對非命名的、相互連接的UNIX域套接字。
**(18) 終端I/O**
1、終端設備是由位于內核中的終端驅動程序控制的,都有一個輸入隊列和輸出隊列。終端設備的所有特性都包含在termios結構中,該結構有四大標志:c_cflag, c_lflag,c_iflag, c_oflag。使用函數tcgetattr和tcsetattr可以獲得和設置termios結構,而在命令行中可以使用stty命令。
2、終端I/O有兩種不同的工作模式:規范模式輸入處理(以行為單位處理)和非規范模式輸入處理(不以行為單位處理輸入數據)。
**(19) 偽終端**
1、偽終端這個術語暗示對于一個應用程序而言,它看上去像一個終端,但實際上應用程序被欺騙了。從內核角度看,偽終端看起來像一個雙向管道。而事實上Solaris的偽終端就是用STREAMS構建的。
2、一些相關的調用函數。Posix_openpt函數用來打開下一個可用的偽終端主設備。用于更改權限的兩個函數是grantpt和unlockpt。確定路徑名用ptsname函數。
3、當我們用pty來執行另外一個程序時,該程序在一個它自己的會話中執行,并和一個偽終端連接。具體對偽終端的應用主要有以下幾個。Utmp文件、作業控制交互、檢查長時間運行程序的輸出、script程序、運行協同進程、用非交互模式驅動交互式程序。
**(20) 數據庫函數庫**
1、本章詳細介紹了一個數據庫函數庫的設計與實現。此函數庫包括的一些函數有:數據庫的打開與關閉函數:db_open, db_close;存儲和刪除一條記錄:db_store,db_delete;從數據庫獲取一條記錄:*db_fetch;訪問數據庫所有記錄的兩個函數:db_rewind, *db_nextrec。
2、數據庫被建立時創建兩個文件:索引文件和數據文件。索引文件的數據通常使用散列法或B+樹來組織,從而提高數據的訪問速度。對于進程對數據庫數據的訪問,有集中式和非集中式兩種實現方法。集中式是指由一個數據庫進程作為數據庫管理者,所有的數據庫訪問工作由此進程完成,其它進程通過IPC與此中心進程聯系。非集中式是指每個庫函數獨立申請并發控制,然后自己調用I/O函數。
**(21)與網絡打印機通信**
1、本章實現了兩個程序:一個打印假脫機守護進程,用以將作業發送到打印機;一個命令行程序,用以將打印作業提交到假脫機守護進程。與網絡打印機通信使用的是網絡打印協議(IPP),而它建立在HTTP和TCP/IP的基礎之上。
總結:這是一本經典的書,對于unix 程序員來說,本書一直遵循三個標準來進行編寫。
(1). iso c ,ieee posix ,The single unix specification 這三個標準一直貫穿始終。
(2). 在某些方面還提到了**limit **這個概念,對于可移植性來說非常重要。
(3). 區分了標準io 和文件io 及其區別,及其文件描述符的重要性。
(4). 還有高級io 的4種方式(阻塞,非阻塞,select ,異步驅動模型)等好多有用的知識。
(5). linux中 七種的通信方式,無名管道,有名管道,信號,ipc(共享內存,消息隊列,信號燈),還有 socket ,分別由unix ,貝爾實驗室,伯克利分校實驗室 繼承而來的幾套標準。
(6) . 討論的偽終端 更是非常的透徹,主設備,從設備的關系,以及偽設備運行在從設備上的原理和用處,
(7). 本書還深刻講解了 進程,線程 的一些同步機制,和互斥鎖,類似pv 操作的東西。
(8). 本書給我最大的感受就是,糾正了好多的編程的習慣,錯誤的認識,提高了我的編程的視角和高度,全面的從系統出發,從全局出發,如 其linux pam 機制([http://www.chinaunix.net/old_jh/4/390136.html](http://www.chinaunix.net/old_jh/4/390136.html))查閱相關資料。
- 前言
- 讀《Linux內核設計與實現》我想到了這些書
- 夢想的啟航,那些年,那些書
- C++和Windows平臺的一些書籍
- java一路走來
- 《Android入門之旅》
- 致我們終將逝去的青春-PHP篇
- 多讀書,讀好書
- 這些年,那些我們一起讀過的代碼
- C++碼農要讀的經典
- 閱讀IT類圖書,能夠收獲什么
- 讀完《大數據時代》的一點兒心得
- 這些日子我讀過的《java編程思想》
- 關于C,看過的一些書
- Android系統深度游
- 《《內存和性能優化》》給我帶來的!
- 「書評」SAP內存計算——HANA
- 書籍記錄了我技術的成長歷程
- 那一年讀過的技術經典書
- 【時間規劃】C/C++發展之路--讀書
- UNIX 環境高級編程之我見
- 游戲開發圖書推薦--我讀過的技術經典圖書
- 自己動手寫操作系統-經典書籍
- 游戲升級之路
- 《SQL Server 2005開發技術大全》分享一本書
- 書,永遠的朋友
- 學生時代的書單
- 追求技術之路 - 那些陪伴我的書籍
- 經典書籍--好書很多,重要的是有個目標,有個規劃
- android系統深入開發
- 這些年一路相伴的書
- 從零開始學
- 這些年我讀過的技術經典圖書(附電子版下載地址)
- 書--益友--從不孤單
- 給自己時間沉淀下來
- 那些支持我學習與工作的良師益友
- 文章千古事、得失寸心知
- 從Linux 驅動到游戲可視化轉行要讀的書
- 那些年,我們一起讀過的《JAVA與模式》
- 往事不堪回首 -- 多讀書
- 我程序人生的啟蒙書
- 一個不喜歡讀書的Javaer的讀書單
- 一本書,讓我走上編程之路
- 程序員讀書的五重天
- 大學那會兒,我讀過的技術經典圖書
- C語言高手進階的三碟小菜和一盤大餐