#include<unistd.h>int dup(int file_descriptor);int dup2(int file_descriptor_one , int file_descriptor_two);
dup調用的目的是開啟一個新的檔案描述符,這與open調用有點類似。不同之處是,dup調用建立的新檔案描述符與作為它的參數的那個已有檔案描述符指向同一個檔案(或管道)。dup2它所建立的新檔案描述符或者與參數file_descriptor_two相同,或者是第一個大於該參數的可用值。
用close和dup函數對檔案描述符進行處理
檔案描述符 初始值 關閉檔案描述符0後 dup調用後
0 標準輸入 {已關閉} 管道檔案描述符
1 標準輸出 標準輸出
標準輸出
2 標準錯誤 輸出標準錯誤輸出
標準錯誤輸出
3 管道檔案描述符 管道檔案描述符
管道檔案描述符
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>int main(){ int data_processed; int file_pipes[2]; const char some_data[] = "123"; pid_t fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == (pid_t)0) { close(0); dup(file_pipes[0]); close(file_pipes[0]); close(file_pipes[1]); execlp("od", "od", "-c", (char *)0); exit(EXIT_FAILURE); } else { close(file_pipes[0]); data_processed = write(file_pipes[1], some_data, strlen(some_data)); close(file_pipes[1]); printf("%d - wrote %d bytes\n", (int)getpid(), data_processed); } } exit(EXIT_SUCCESS);}
命令管道:FIFO
我們可以在命令列上建立具名管道,也可以在程式中建立它。過去,命令列上用來差un關鍵具名管道的程式是mknod,如下所示:
mknod filename p
但mknod命令並未出現在X/OPEN規範的命令列表中。所以可能並不是所有的類unix系統都可以這樣做。我們推薦使用的命令列是:
mkfifo filename
在程式中,我們可以使用兩個函數調用來建立管道,如下所示:
#include<sys/types.h>#include<sys/stat.h>int mkfifo( const char *filename , mode_t mode);int mknod(const char *filename , mode_t mode | S_IFIFO , (dev_t ) 0 );
建立具名管道
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>int main(){ int res = mkfifo("/tmp/my_fifo", 0777); if (res == 0) printf("FIFO created\n"); exit(EXIT_SUCCESS);}
訪問FIFO檔案
(1)首先,我們來嘗試讀這個(空的)FIFO檔案
$ cat </tmp/my_fifo
(2)現在,嘗試向FIFO寫資料。你必須用另一個中斷來執行下面的命令,因為第一個命令現在被掛起已等到資料出現在FIFO中。
$ echo "hello world" > /tmp/my_fifo
(3)我們可以將第一個命令放在後台執行,這樣即可一次執行兩個命令。
$ cat < /tmp/my_fifo &
$ echo "hello world" > /tmp/my_fifo
當使用open()來開啟
FIFO檔案時,O_NONBLOCK旗標會有影響
1、當使用O_NONBLOCK 旗標時,開啟FIFO 檔案來讀取的操作會立刻返回,但是若還沒有其他進程開啟FIFO 檔案來讀取,則寫入的操作會返回ENXIO 錯誤碼。
2、沒有使用O_NONBLOCK 旗標時,開啟FIFO 來讀取的操作會等到其他進程開啟FIFO檔案來寫入才正常返回。同樣地,開啟FIFO檔案來寫入的操作會等到其他進程開啟FIFO 檔案來讀取後才正常返回。
傳回值
若成功則返回0,否則返回-1,錯誤原因存於errno中。
錯誤碼
EACCESS 參數pathname所指定的目錄路徑無可執行檔許可權
EEXIST 參數pathname所指定的檔案已存在。
ENAMETOOLONG 參數pathname的路徑名稱太長。
ENOENT 參數pathname包含的目錄不存在
ENOSPC 檔案系統的剩餘空間不足
ENOTDIR 參數pathname路徑中的目錄存在但卻非真正的目錄。
EROFS 參數pathname指定的檔案存在於唯讀檔案系統內。
// Let's start with the header files, a #define and the check that the correct number// of command-line arguments have been supplied.#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#define FIFO_NAME "/tmp/my_fifo"int main(int argc, char *argv[]){ int res; int open_mode = 0; int i; if (argc < 2) { fprintf(stderr, "Usage: %s <some combination of\ O_RDONLY O_WRONLY O_NONBLOCK>\n", *argv); exit(EXIT_FAILURE); }// Assuming that the program passed the test, we now set the value of open_mode// from those arguments. for(i = 1; i < argc; i++) { if (strncmp(*++argv, "O_RDONLY", 8) == 0) open_mode |= O_RDONLY; if (strncmp(*argv, "O_WRONLY", 8) == 0) open_mode |= O_WRONLY; if (strncmp(*argv, "O_NONBLOCK", 10) == 0) open_mode |= O_NONBLOCK; }// We now check whether the FIFO exists and create it if necessary.// Then the FIFO is opened and output given to that effect while the program// catches forty winks. Last of all, the FIFO is closed. if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0777); if (res != 0) { fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO\n", getpid()); res = open(FIFO_NAME, open_mode); printf("Process %d result %d\n", getpid(), res); sleep(5); if (res != -1) (void)close(res); printf("Process %d finished\n", getpid()); exit(EXIT_SUCCESS);}