LINUX提供了很多進階的I/O函數,我們介紹和網絡程式設計相關的幾個,在特定情況下可以産生很高的性能。主要分為3類:
1、建立檔案描述符的函數,pipe,dup,dup2函數;
2、讀寫資料的函數,readv,writev,sendfile,mmap,munmap,splice,tee函數;
3、用于控制I/O行為和屬性的函數,fcntl()函數。
1、pipe函數
pipe用于建立一個管道實作程序間通信。這裡隻介紹基本使用。
參數是包含兩個int型整數的數組指針。(數組指針隻是一個指針變量,它占有記憶體中一個指針的存儲空間。指針數組是多個指針變量,以數組形式存在記憶體當中,占有多個指針的存儲空間。)成功時傳回0,并将一對打開的檔案描述符值放入參數指向的數組。
(1)fd[0],fd[1]構成管道的兩端,并且,fd[0]隻能用于從管道讀取資料,fd[1]用于往管道寫資料。如果要實作雙向的資料傳輸,就要建立兩個管道。
(2)預設情況下,這一對檔案描述符都是阻塞的,如果我們用read讀取一個空的管道,将會被阻塞,直到管道有資料可讀。如果應用程式把fd[0],fd[1]設定為非阻塞的,則read,write會有不同的行為,後面再說。
(3)如果fd[1]寫端的引用計數件為0,則讀端fd[0]read将會傳回0,表示讀到了檔案結束符EOF,同理,在讀端引用計數變為0,寫端調用write會失敗,并引發SIGPIPE信号。這點後面具體介紹。
(4)管道内傳輸的是位元組流,和TCP位元組流是一樣的概念,隻不過管道最多能寫入的資料大小是有限制的,也可以用fcntl函數來修改管道容量。
socket基礎API也有一個sockerpair函數可以建立一個可讀可寫的雙向管道,不過隻支援本地使用UNIX.
2.dup,dup2函數
有時候我們想标準輸入重定向到一個檔案,或者把标準輸出重定向到一個網絡連接配接(比如CGI程式設計,我們線上填寫表格那種)。可以用複制檔案描述符的函數dup,dup2來實作:
dup建立一個新的檔案描述符,并且他和原來的檔案描述符指的是同一個檔案,管道或者網絡連接配接。并且傳回的檔案描述符是目前系統可用的最小的整數,dup2傳回的檔案描述符不小于第二個參數的值。(注意新的檔案描述符不繼承原來檔案描述符的屬性)
3.readv,writev函數
readv函數将資料從檔案描述符讀到分散的記憶體塊中,叫分散讀,writev相反,稱為集中寫。
其中iovec是秒數記憶體區域的結構體,count是記憶體塊的數量,即vector數組的長度。
4.sendfile函數
這個函數直接在核心中完成兩個檔案描述符的資料傳輸,避免了使用者資料緩沖區和核心資料緩沖區的資料拷貝,稱為零拷貝,效率很高。不用設定緩存也不用讀取操作。
out_fd是待寫入内容的檔案描述符,in_fd是待讀出内容的檔案描述符。注意,這裡的in_fd必須指向真實的檔案,不能是socket和管道,out_fd必須是一個socket。是以,sendfile幾乎專門為了在網絡上傳輸檔案設計的。
5、mmap和munmap函數
mmap函數用于申請一段記憶體空間。可用于程序間通信的共享記憶體或者直接将檔案映射其中,munmap用于釋放申請的記憶體空間。
start參數允許使用者使用某個特定位址作為記憶體起始位址。如果設為NULL,系統配置設定一個位址。prot用來指定記憶體段的通路權限。後面我們會進一步探讨如何實作記憶體共享。
6、splice函數
用于在兩個檔案描述符間移動資料,也是零拷貝操作。
注意,必須至少有一個是管道檔案描述符,成功時傳回移動資料的位元組數量。
7、tee函數
tee函數用于在兩個管道檔案描述符之間複制資料,也是零拷貝操作。注意這裡是複制,不是移動。
成功時傳回複制位元組數。
8、fcntl函數(file control)
提供了對檔案描述符的各種控制操作。
cmd指定執行何種類型的操作,還有可能有第三個參數。
在網絡程式設計中,此函數經常用來将一個檔案描述符設定為非阻塞的。
還有關于信号控制的内容,後面再說。