對于 Dup2 的理解:
源代碼:
?
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include < string .h> 5 #include <time.h> 6 7 #define MSGSIZE 20 8 #define READ 0 9 #define WRITE 1 10 11 int main( int argc, char const * argv[]) 12 { 13 int p[ 2 ], bytes, res, c; 14 char inbuf[ 10240 ]; 15 int pid; 16 printf( " %c " , 11 ); 17 if (pipe(p) == - 1 ){ // creat the pipe , if pipe is built failed , exit . 18 perror( " pip call " ); 19 exit( 1 ); 20 } 21 pid = fork(); 22 if (pid != 0 ){ // creat parent pid and child pid. 23 close(p[READ]); // close parent pipe read 24 dup2(p[WRITE], 1 ); 25 close(p[WRITE]); // close parent pipe write 26 execlp(argv[ 1 ], argv[ 1 ], NULL); 27 } 28 else { 29 30 close(p[WRITE]); // close child pipe write 31 32 dup2(p[READ], 0 ); 33 34 close(p[READ]); // close child pipe read 35 36 execlp(argv[ 2 ], argv[ 2 ], NULL); 37 } 38 return 0 ; 39 }
?
通過命令行輸出:
./a.out “l(fā)s” “ps”
僅僅在終端執(zhí)行了 ps 的命令, 而沒有看到 ls 命令的結果。
因此,開始走入了第一個誤區(qū):父進程沒有執(zhí)行
通過調試 在父進程執(zhí)行 if 條件中加入以下代碼:
if(pid != 0){
printf("4556\n");
close(p[READ]);
dup2(p[WRITE], 1);
close(p[WRITE]);
printf("4556\n");
execlp(argv[1], argv[1], NULL);
}
加入了 2 個 printf , 但是只有 dup2 上面的 printf 結果輸出到屏幕上,因此我注釋了 dup2(p[WRITE], 1); 結果在父進程 if 語句中的 dup2 后面的命令都執(zhí)行并且輸出到屏幕上了。通過查找 dup2 命令發(fā)現(xiàn)了重定向的強大之處。
先解釋下 dup2 命令,
int dup2(int filedes, int filedes2);
說明:
用 dup2 則可以用 filedes2 參數(shù)指定新描述符的數(shù)值。如果 filedes2 已經打開,則先將其關閉。如若 filedes 等于 filedes2 ,則返回 filedes2 ,而不關閉它。
dup2(p[WRITE], 1); 這句話可以理解為將標準輸出重定向到 p[WRITE], 因此在這句話后面的所有 printf 語句打印或者 exec 執(zhí)行的內容都輸入到了 p[WRITE] 中。剛開始有個迷惑,就是既然已經 close ( 1 )了,為什么還能輸入到 p[WRITE] 中,通過自己的直覺判斷,應當是 close(1) 關閉了屏幕的輸出,但是它有緩沖區(qū)保存 printf 打印出的內容,并且由于重定向的關系,輸進了 p[WRITE] 中。
?
代碼:
?
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include < string .h> 5 #include <time.h> 6 7 #define MSGSIZE 20 8 #define READ 0 9 #define WRITE 1 10 11 int main( int argc, char const * argv[]) 12 { 13 int p[ 2 ], bytes, res, c; 14 char inbuf[ 10240 ]; 15 int pid; 16 printf( " %c " , 11 ); 17 if (pipe(p) == - 1 ){ // creat the pipe , if pipe is built failed , exit . 18 perror( " pip call " ); 19 exit( 1 ); 20 } 21 pid = fork(); 22 if (pid != 0 ){ // creat parent pid and child pid. 23 close(p[READ]); // close parent pipe read 24 dup2(p[WRITE], 1 ); 25 close(p[WRITE]); // close parent pipe write 26 printf( " 123!\n " ); 27 execlp(argv[ 1 ], argv[ 1 ], NULL); 28 perror( " execlp " ); // error output 29 } 30 else { 31 while ( 1 ){ 32 res = read(p[READ], inbuf, 10240 ); 33 if (res> 0 ) 34 printf( " %s\n " , inbuf); 35 break ; 36 } 37 38 close(p[WRITE]); // close child pipe write 39 40 dup2(p[READ], 0 ); 41 42 close(p[READ]); // close child pipe read 43 44 execlp(argv[ 2 ], argv[ 2 ], NULL); 45 } 46 return 0 ; 47 }
?
?
?
通過在子進程中用 while(1) 循環(huán)讀取 p[READ] 內容,發(fā)現(xiàn)讀出了父進程本應在屏幕上打印的內容,因此父進程是執(zhí)行了所有命令行,只是通過重定向命令存到了 p[WRITE] 管道中。
由于有 dup2(p[READ], 0) 命令,因此猜測標準輸入的文件描述符定向到了 p[READ] , 因此如果猜測沒錯,通過 getchar() 讀取文件標準輸入并把 P[READ] 的內容輸出到屏幕上則證明我猜想沒錯。
代碼 :
?
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include < string .h> 5 #include <time.h> 6 7 #define MSGSIZE 20 8 #define READ 0 9 #define WRITE 1 10 11 int main( int argc, char const * argv[]) 12 { 13 int p[ 2 ], bytes, res, c; 14 char inbuf[ 10240 ]; 15 int pid; 16 printf( " %c " , 11 ); 17 if (pipe(p) == - 1 ){ // creat the pipe , if pipe is built failed , exit . 18 perror( " pip call " ); 19 exit( 1 ); 20 } 21 pid = fork(); 22 if (pid != 0 ){ // creat parent pid and child pid. 23 close(p[READ]); // close parent pipe read 24 dup2(p[WRITE], 1 ); 25 close(p[WRITE]); // close parent pipe write 26 printf( " 123!\n " ); 27 execlp(argv[ 1 ], argv[ 1 ], NULL); 28 perror( " execlp " ); // error output 29 } 30 else { 31 // while(1){ 32 // res = read(p[READ], inbuf, 10240); 33 // if(res>0) 34 // printf("%s\n", inbuf); 35 // break; 36 // } 37 38 close(p[WRITE]); // close child pipe write 39 40 dup2(p[READ], 0 ); 41 while ((c=getchar()) != - 1 ){ 42 printf( " %c " , c); 43 } 44 close(p[READ]); // close child pipe read 45 46 execlp(argv[ 2 ], argv[ 2 ], NULL); 47 } 48 return 0 ; 49 }
?
通過在 dup2(p[READ], 0) 后面 while 循環(huán)讀入輸入流輸入的字符并且打印出來, 發(fā)現(xiàn)結果果然是 p[READ] 的內容,猜疑沒錯。
為了更清楚的理解 dup2 的重定向含義,想理解 dup2(fd,0) 和 dup2(0,fd) 功能相同嗎?
為了得到答案,找些資料發(fā)現(xiàn),答案是不同。
?
測試代碼:
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <fcntl.h> 4 5 #define BUFMAXSIZE 4096 6 7 int main( int argc, char * argv[]) 8 { 9 int fd; 10 int n; 11 char buf[BUFMAXSIZE]; 12 int fs; 13 fs = open( " test " , O_RDWR); 14 if ((fd = open( " duan " , O_RDWR )) == - 1 ) 15 { 16 perror( " open error! " ); 17 return ( 1 ); 18 } 19 20 dup2(fd, 1 ); // dup2(0,fd); 21 22 while ((n = read(fs, buf, BUFMAXSIZE)) > 0 ) 23 { 24 printf( " begin to read...\n " ); 25 if (write(STDOUT_FILENO, buf, n) != n) 26 { 27 perror( " write error! " ); 28 return ( 1 ); 29 } 30 printf( " end to write...\n " ); 31 } 32 if (n < 0 ) 33 { 34 perror( " read error " ); 35 return ( 1 ); 36 } 37 38 return 0 ; 39 }
?
?
dup(fd, 0) 這段代碼測試, 打印出了 duan 文件里面的內容。
之后創(chuàng)建個文件 Levi 里面寫和 duan 文件不同的內容。
通過 ./a. out < Levi 輸出:
第一個輸出是 dup(fd, 0) 輸出了 Duan 文件的內容。即是 fd 的內容
第二個輸出是 dup(0, fd) 輸出了 Levi 文件的內容。即是 通過文件重定向到標準輸入的內容。
從圖中的輸出結果已經可以看到兩者的區(qū)別了。
第一種 dup2(fd,0) 之前已經將 fd 初始化指向到文本 Duan 了,
并且不會被后面的代碼所修改。
第二種 dup2(0,fd) 則將 fd 重新指向到文件描述符 0 所代表的文件(即終端標準輸入)了。
那么可以看到,程序的執(zhí)行中不會再讀取 Duan 文件了。
而是進入了一種交互模式。
另外,這時“輸入重定向”也可以生效了。
文件描述符 0 被 “ <” 重定向到 Duan 了
所以,這里直接輸出了該文本的內容。
dup2(fd,0) 相當于“輸入重定向”的功能,
dup2(0,fd) 不是表示 fd 所指的文件接收來自終端的輸入,因為, fd 已經不再指向原來的那個文件了。
它和文件描述符 0 已經在共享同一個文件表項(即指向終端標準輸入的那個表項)了。
“ 輸出重定向”的功能可以用 dup2(fd ,1) 替代。
dup2(fd,1) 和 dup2(1,fd) 也是大同小異。
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
