Linux文件系統(tǒng)結(jié)構(gòu)
調(diào)用Open函數(shù)會發(fā)生什么
對同一個文件打開多次會怎樣
父子進程的文件關(guān)系
重定向的實現(xiàn)
管道的實現(xiàn)
概述
int fd = open(pathname, flags, mode);
關(guān)于文件讀取與寫入,我們總是能用到open函數(shù),返回一個文件描述符,然后就可以對fd進行操作。同樣,調(diào)用socket accept函數(shù)也會返回一個fd。所以問題在于Linux是如何處理fd,使得我們可以處理真正的磁盤IO。
Linux文件系統(tǒng)結(jié)構(gòu)

1)進程級文件描述符表 Process File Table
2)系統(tǒng)級打開文件表 System File Table
3)系統(tǒng)i-Node表
調(diào)用Open函數(shù)會發(fā)生什么

每次open時,會在進程文件描述符表新增數(shù)據(jù)(一個int型fd 和一個指針),指針指向系統(tǒng)打開文件表。系統(tǒng)文件表會表明這個打開文件的權(quán)限(status 讀、寫等),當(dāng)前打開文件的偏移量(offset 即下次讀取時的位置),指向系統(tǒng)i-Node表的指針等。因此我們可以知道,fd是針對進程的概念,不同進程的相同fd很大可能并沒有任何關(guān)系
對同一個文件打開多次會怎樣
Process A:?
fd1 = open("/var/file1", O_RDONLY);?
fd2 = open("/var/file2", O_RDWR);?
fd3 = open("/var/file1", O_WRONLY);
Process B:?
fd1 = open("/var/file1", O_RDONLY);?
fd2 = open("/var/file3", O_RDONLY);

不管是相同進程還是不同進程,只要調(diào)用open就會有一個新的fd和一個新的系統(tǒng)打開文件表的對應(yīng)項,所以對這些fd進行讀取操作并不會造成相互影響。因為系統(tǒng)文件表是獨立的,offset也是獨立的
父子進程的文件關(guān)系

調(diào)用fork后,雖然父子進程都有獨立的進程文件描述符表,但所有fd所對應(yīng)的文件表都會保持完全一致,因此當(dāng)我們在子進程讀取fd1時,父進程的file offset也會同時變化,也就造成了一些奇怪的現(xiàn)象,所以對待fd的讀寫要謹慎處理
重定向的實現(xiàn)

dup2(close_this_fd = open("my.txt", O_WRONLY), 1);
程序的輸出會直接輸出到標(biāo)準(zhǔn)輸出,但以上語句會將現(xiàn)有進程的標(biāo)準(zhǔn)輸出(fd = 1)重定向到my.txt對應(yīng)的文件表。因此輸出后,my.txt將會展示剛才程序的輸出。這也就是 out > my.txt的實現(xiàn)
管道的實現(xiàn)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void){
????int pfds[2];
? ? pipe(pfds);
? ? ?if (!fork()) {
? ? ????????close(1); /* close normal stdout */
?????????????dup(pfds[1]); /* make stdout same as pfds[1] */
?????????????close(pfds[0]); /* we don't need this */
?????????????execlp("ls", "ls", NULL);
????} else {
?????????close(0); /* close normal stdin */
?????????dup(pfds[0]); /* make stdin same as pfds[0] */
?????????close(pfds[1]); /* we don't need this */
?????????execlp("grep", "SOMETHING", NULL);
????}
????return 0;}

管道的總體原理就是(ls | grep)
1)A/B兩個進程,B進程是A的子進程,A進程執(zhí)行l(wèi)s?,B進程執(zhí)行g(shù)rep
2)將A進程的標(biāo)準(zhǔn)輸出通過dup2命令重定向到一個buffer區(qū)
3)B進程的標(biāo)準(zhǔn)輸入通過dup2重定向到同一個buffer區(qū)
4)B進程獲取到A進程的輸出并執(zhí)行自己的邏輯
參考文章
File System, Kernel Data Structures, and Open Files