dup和dup2

dup和dup2

最近寫那個 myshell 需要用到多管道 以及重定向方面的知識,實現過程中 其中避不開的一個函數就是我的標題dup 與dup2
它們的作用都是用來複制一個文件的描述符。它們經常用來重定向進程的stdin(0)、stdout(1)和stderr(2)。
函數原型

#include <unistd.h>  
int dup( int oldfd );  
int dup2( int oldfd, int targetfd );

dup()函數

利用函數dup,我們可以複製一個描述符。傳給該函數一個既有的描述符,它就會返回一個新的描述符,這個新的描述符是傳給它的描述符的拷貝。這意味着,這兩個描述符共享同一個數據結構。

dup2()函數

dup2函數跟dup函數相似,但dup2函數允許調用者規定一個有效描述符和目標描述符的id。dup2函數成功返回時,目標描述符(dup2函數的第二個參數)將變成源描述符(dup2函數的第一個參數)的複製品,換句話說,兩個文件描述符現在都指向同一個文件,並且是函數第一個參數指向的文件。下面我們用一段代碼加以說明:

int oldfd;  
oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 );  
dup2( oldfd, 1 );  
close( oldfd ); 

這是一段用來演示的代碼

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>   
int main()  
{  
    int pfds[2];  

    if ( pipe(pfds) == 0 ) {  

    if ( fork() == 0 ) {  

        close(1);  
        dup2( pfds[1], 1 );  
        close( pfds[0] );  
        execlp( "ls", "ls", "-l", NULL );  

    } else {  

        close(0);  
        dup2( pfds[0], 0 );  
        close( pfds[1] );  
        execlp( "wc", "wc", "-l", NULL );  

    }  

    return 0;  
}  

在示例代碼中,首先在第9行代碼中建立一個管道,然後將應用程序分成兩個進程:一個子進程(第13–16行)和一個父進程(第20–23行)。接下來,在子進程中首先關閉stdout描述符(第13行),然後提供了ls –l命令功能,不過它不是寫到stdout(第13行),而是寫到我們建立的管道的輸出端,這是通過dup2函數來完成重定向的。在第14行,使用dup2 函數把stdout重定向到管道(pfds[1])。之後,馬上關掉管道的輸入端。然後,使用execlp函數把子進程的映像替換爲命令ls –l的進程映像,一旦該命令執行,它的任何輸出都將發給管道的輸入端。

現在來研究一下管道的接收端。從代碼中可以看出,管道的接收端是由父進程來擔當的。首先關閉stdin描述符(第20行),因爲我們不會從機器的鍵盤等標準設備文件來接收數據的輸入,而是從其它程序的輸出中接收數據。然後,再一次用到dup2函數(第21行),讓管道的輸入端作爲輸入,這是通過讓文件描述符0(即常規的stdin)重定向到pfds[0]實現的。關閉管道的stdout端(pfds[1]),因爲在這裏用不到它。最後,使用 execlp函數把父進程的映像替換爲命令wc -l的進程映像,命令wc -l把管道的內容作爲它的輸入(第23行)。

那個多管道確實蠻難寫的有想法寫不出來代碼,好不容易寫出來代碼,卻是個段錯誤!!!
最近確實感覺腦子越來越不夠用了 哎

發佈了39 篇原創文章 · 獲贊 22 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章