下面兩個函數都可用來復制一個現存的文件描述符:
#include<unistd.h>
int dup(int filedes);
int dup2(int filedes,int filedes2);
兩函數的返回值:若成功則返回新的文件描述符,若出錯則返回-1
由dup返回的新文件描述符一定是當前可用文件描述符中的最小值。用dup2則可以用filedes2參數指定新描述符的數值。如果filedes2已經打開,則現將其關閉。如若filedes等於filedes2,則dup2返回filedes2,而不關閉它。
這些函數返回的新文件描述符與參數filedes共享同一文件表項。如圖所示,我們假定執行了:
newfd=dup(1);
當此函數開始執行時,假定下一個可用的描述符是3(這是非常可能的,因為0,1和2由shell打開)。因為兩個描述符指向同一文件表項,所以它們共享同一文件狀態標志(讀、寫、添加等)以及同一當前文件偏移量。
每個文件描述符都有它自己的一套文件描述符標志。
復制一個描述符的另一種方式是使用fcntl函數,實際上,可調用:
dup(filedes);
等效於
fcntl(filedes,F_DUPFD,0);
而調用
dup2(filedes,filedes2);
等效於
close(filedes2);
fcntl(filedes,F_DUPFD,filedes2);
在后一種情況下,dup2並不完全等效於close加上fcntl。它們之間的區別是:
1)dup2是一個原子操作,而close及fcntl則包括兩個函數調用,有可能在close和fcntl之間插入執行信號捕獲函數,它可能修改文件描述符。
2)dup2和fcntl有某些不同的errno。
重點解釋兩個地方:
-
第3幅圖,要執行
dup2(fd, 1);
,文件描述符1原本指向tty
,現在要指向新的文件somefile
,就把原來的關閉了,但是tty
這個文件原本有兩個引用計數,還有文件描述符save_fd
也指向它,所以只是將引用計數減1,並不真的關閉文件。 -
第5幅圖,要執行
dup2(save_fd, 1);
,文件描述符1原本指向somefile
,現在要指向新的文件tty
,就把原來的關閉了,somefile
原本只有一個引用計數,所以這次減到0,是真的關閉了。
#include<unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup() uses the lowest-numbered unused descriptor for the new descriptor.
dup2() makes newfd be the copy of oldfd, closing newfd first ifnecessary, but note the following:
*If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
*If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.
1)這兩個函數我們可以用來復制文件描述符。
2)其中oldfd和newfd分別是復制前文件描述符和復制后的文件描述符。
3)這兩個函數的調用都將復制文件描述符oldfd,且他們的返回值都為新的文件描述符。
4)不同點是:dup()的返回值是最小的未用文件描述符;dup2()的返回值是預先制定的文件描述符newfd。
5)對於dup2(),如果文件描述符newfd正在被使用,則先關閉newfd;如果newfd同oldfd,則不關閉該文件正常返回。
PS:這是我自己對書上的話進行的分類。
2.首先要弄懂的話,還要對文件描述符了解的清晰:
關系:進程---(擁有)--->(若干個)文件描述符()---(對應)--->文件
|--->文件秒素符(0)
|--->文件描述符(1)--->文件(1)
某進程(n)--|--->文件描述符(2)
|--->文件描述符(3)--->文件(3)
|.
|.
|.
|--->文件描述符(1023)--->文件(...)
PS1:由一次open()函數打開的文件是可以有很多個描述符與之相連的;
PS2:Linux中每個進程可以有1024個文件描述符;
PS3:文件描述符前三位0、1、2分別對應:
STDIN_FILENO 0 標准輸入文件
STDOUT_FILENO 1 標准輸出文件
STDERR_FILENO 2 標准錯誤輸出文件
因此就可以較好的開始理解dup(int oldfd)和dup2(int oldfd, int newfd)函數是如何工作的:
dup()比較好了解:
系統分配一個新的、未用過的、值為最小的文件描述符指向dup()函數內的參數oldfd所指向的文件,並返回該值。
dup2()比較難理解:
1)dup2()先看看oldfd是不是一個有效的文件描述符,如果不是則調用失敗,newfd文件描述符也不關閉;
2)如果oldfd是一個有效的文件描述符,則檢測newfd是否被使用,如在使用,則將其關閉,並將newfd指向oldfd所指向的文件,並返回newfd;
3)如果newfd同oldfd,則不關閉該文件正常返回。