一 管道的作用
通常把一個進(jìn)程的輸出通過管道連接到另一個進(jìn)程的輸入。
二 popen和pclose函數(shù)
#include <stdio.h>
FILE
*popen(
const
char
*command,
//是要運行的程序名和相應(yīng)的參數(shù)
const
char
*
open_mode
//必須是“r”或者“w”,如果是其它值,errno將返回EINVAL
);
int
pclose(FILE *stream_to_close);
popen() 函數(shù)通過創(chuàng)建一個管道,調(diào)用 fork 產(chǎn)生一個子進(jìn)程,執(zhí)行一個 shell 以運行命令來開啟一個進(jìn)程。
pclose()調(diào)用只在popen啟動的進(jìn)程結(jié)束后才返回,如果調(diào)用pclose函數(shù)時它仍在運行,pclose調(diào)用將等待該進(jìn)程的結(jié)束。
例:
#include <stdio.h>
#include
<stdlib.h>
#include
<unistd.h>
#include
<
string
.h>
int
main(){
FILE
*
read_fp;
//要讀取的文件描述符
char
buffer[BUFSIZ+
1
];
//用來存儲讀到的文件信息
int
chars_read;
//實際讀取的元素個數(shù)
memset(buffer,
'
\0
'
,
sizeof
(buffer));
//將數(shù)組清零初始化
read_fp
=popen(
"
cat test*.c | wc -l
"
,
"
r
"
);
//創(chuàng)建管道,用于顯示所有test*.c文件的字?jǐn)?shù)
if
(read_fp!=
NULL){
chars_read
=fread(buffer,
sizeof
(
char
),BUFSIZ,read_fp);
//從一個文件流中讀數(shù)據(jù),最多讀取count個元素,每個元素size字節(jié),如果調(diào)用成功返回實際讀取到的元素個數(shù),如果不成功返回 0
while
(chars_read>
0
){
buffer[chars_read
-
1
]=
'
\0
'
;
//清除回車符
printf(
"
Reading:-\n %s\n
"
,buffer);
chars_read
=fread(buffer,
sizeof
(
char
),BUFSIZ,read_fp);
}
pclose(read_fp);
//關(guān)閉管道
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
使用shell的一個不太好的影響:針對每個popen調(diào)用,不僅要啟動一個被請求的程序,還要啟動一個shell,即每個popen調(diào)用將多啟動兩個進(jìn)程。從節(jié)省系統(tǒng)資源的角度來看,popen函數(shù)的調(diào)用成本略高,而且對目標(biāo)命令的調(diào)用比正常方式要慢一些。
三 pipe函數(shù)
#include <unistd.h>
int
pipe(
int
fd[
2
]);
pipe函數(shù)的參數(shù)是一個由兩個整數(shù)類型的文件描述符組成的數(shù)組的指針,兩個返回的文件描述符以一種特殊的方式連接起來,寫到fd[1]的所有數(shù)據(jù)都可以從fd[0]讀回來,數(shù)據(jù)基于先進(jìn)先出的原則(FIFO)進(jìn)程處理。
對一個已關(guān)閉寫數(shù)據(jù)的管道做read調(diào)用將返回0而不是阻塞,讀取無效的文件描述符將看作是一個錯誤并返回-1
?
如果跨越fork調(diào)用使用管道,就會有兩個不同的文件描述符可以用于向管道寫數(shù)據(jù),一個在父進(jìn)程中,一個在子進(jìn)程中。只有把父子進(jìn)程中的針對管道的寫文件描述符都關(guān)閉,管道才會被認(rèn)為是關(guān)閉了,對管道的read調(diào)用才會失敗。
管道的讀寫規(guī)則:
1 從管道中讀取數(shù)據(jù)
- 如果管道的寫端不存在,則認(rèn)為已經(jīng)讀到了數(shù)據(jù)的末尾,讀函數(shù)返回的讀出字節(jié)數(shù)為0;
- 當(dāng)管道的寫端存在時,如果請求的字節(jié)數(shù)目大于PIPE_BUF,則返回管道中現(xiàn)有的數(shù)據(jù)字節(jié)數(shù),如果請求的字節(jié)數(shù)目不大于 PIPE_BUF,則返回管道中現(xiàn)有數(shù)據(jù)字節(jié)數(shù)(此時,管道中數(shù)據(jù)量小于請求的數(shù)據(jù)量);或者返回請求的字節(jié)數(shù)(此時,管道中數(shù)據(jù)量不小于請求的數(shù)據(jù) 量)。注:(PIPE_BUF在include/linux/limits.h中定義,不同的內(nèi)核版本可能會有所不同。Posix.1要求 PIPE_BUF至少為512字節(jié),red hat 7.2中為4096)。
2 從管道中寫入數(shù)據(jù)
向管道中寫入數(shù)據(jù)時,linux將不保證寫入的原子性,管道緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會試圖向管道寫入數(shù)據(jù)。如果讀進(jìn)程不讀走管道緩沖區(qū)中的數(shù)據(jù),那么寫操作將一直阻塞。
注:只有在管道的讀端存在時,向管道中寫入數(shù)據(jù)才有意義。否則,向管道中寫入數(shù)據(jù)的進(jìn)程將收到內(nèi)核傳來的SIFPIPE信號,應(yīng)用程序可以處理該信號,也可以忽略(默認(rèn)動作則是應(yīng)用程序終止)。
?
例子:
#include <stdio.h>
#include
<stdlib.h>
#include
<unistd.h>
#include
<
string
.h>
int
main(){
const
char
some_data[]=
"
123
"
;
int
file_pipes[
2
];
int
data_processed;
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==
0
){
//子進(jìn)程
close(
0
);
//關(guān)閉標(biāo)準(zhǔn)輸入,即鍵盤輸入
dup(file_pipes[
0
]);
//復(fù)制一個文件描述符
close(file_pipes[
0
]); ?
//關(guān)閉讀操作
close(file_pipes[
1
]);
//關(guān)閉寫操作
execlp(
"
od
"
,
"
od
"
,
"
-c
"
,(
char
*)
0
);
//利用od查看特殊格式的文件內(nèi)容,-c表示ASCII字符或反斜杠序列,(char*)0參數(shù)作用是終止被調(diào)用程序的參數(shù)列表
exit(EXIT_FAILURE);
}
else
{
//主進(jìn)程
close(file_pipes[
0
]);
data_processed
=write(file_pipes[
1
],some_data,strlen(some_data));
//寫入數(shù)據(jù)
close(file_pipes[
1
]);
printf(
"
%d - wrote %d bytes\n
"
,getpid(),data_processed);
}
}
exit(EXIT_SUCCESS);
}
?
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

