嘗試linux下c程式設計之管道
阿新 • • 發佈:2019-01-16
今天試了下管道,感覺挺有意思的~ 現在才發現,原來程序也有這麼多的功能可以實現。
管道分類: 根據程序的相互關係,可以分為:匿名管道與命名管道。
1 匿名管道:管道是父程序和子程序間,或是子程序與子程序間單向的通訊機制,即一個程序傳送資料到管道,另外一個程序從管道中讀出資料。如果需要雙向,或是多項通訊機制,則需要建立兩個活多個管道.
系統負責兩件事:一是寫入管道的資料和讀出管道的資料的順序是相同的,二是資料不會在管道中丟失,除非某個程序過早的退出.
建立管道函式為
int pipe(int pipe[2]); //其中pipe[0]是讀取資料的描述字,pipe[1]是寫資料的描述字
例項:
#include < stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void read_data( int pipes[ ] )
{
int c;
int rc;
close( pipes[ 1 ] ); //由於此函式只負責讀,因此將寫描述關閉(資源寶貴)
while( (rc = read(pipes[ 0 ], &c, 1)) >0 ){ //阻塞,等待從管道讀取資料
putchar( c ); //int 轉為 unsiged char 輸出到終端
}
exit( 0 );
}
void write_data( int pipes[ ] )
{
int c;
int rc;
close( pipes[ 0 ] ); //關閉讀描述字
while( (c=getchar()) >0 ){
rc = write( pipes[ 1 ], &c, 1 ); //寫入管道
if( rc ==-1 ){
perror ("Parent: write");
close( pipes[ 1 ] );
exit( 1 );
}
}
close( pipes[ 1 ] );
exit( 0 );
}
int main( int argc, char*argv[ ] )
{
int pipes[ 2 ];
pid_t pid;
int rc;
rc = pipe( pipes ); //建立管道
if( rc ==-1 ){
perror( "pipes" );
exit( 1 );
}
pid = fork( );
switch( pid ){
case-1:
perror( "fork" );
exit( 1 );
case0:
read_data( pipes ); //相同的pipes
default:
write_data( pipes ); //相同的pipes
}
return0;
}
上述匿名管道是與程序密切相關的。只有有關係的程序才能使用他們。至於兩個不相關的程序則需要用到有名字的管道,即命名管道。
2 命名管道:又稱FIFO (FIRST IN FIRST OUT). 它是檔案系統中的特殊檔案(注意是檔案哦,一般我們可以把它放在/tmp/xxxx裡). 不同的程序開啟相同的命名管道實現類似匿名管道的資料通訊。
ps: Unix/Linux 檔案系統:包括普通檔案,檔案目錄,與特殊檔案(FIFO是其中之一),FIFO檔案像普通檔案一樣,也有讀寫開啟等常用功能。
管道檔案刪除: 程式中可使用unlink()
接觸管道讀寫阻塞: 使用fcntl()
例項:先編譯執行fifoW.c , 再編譯執行fifoW.c fifoR的子程序接受管道資料,fifoW負責寫
/* fifoR.c 負責從管道檔案中讀取資料 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#define FIFO_NAME "/tmp/myfifo2" //定義巨集,指向管道檔案的位置
void read_pipe(){ //子程序, 處理從管道中讀資料
int pipe_fd;
int res;
int c;
int open_mode = O_RDONLY; //設定許可權,為只讀
pipe_fd = open( FIFO_NAME, open_mode ); //開啟管道檔案,並設定開啟許可權,返回int
if( pipe_fd!=-1 ){
while(1){
while( (res = read( pipe_fd, &c, 1 )) >0 ){ //從管道讀資料
putchar( c );
}
fflush( stdout );
}
}else{
exit( 1 );
}
close(pipe_fd);
}
void signal_handler( int n){ //受到子程序退出訊號,結束子程序
int child_status;
wait( &child_status );
printf( "child exited. " );
}
int main( int argc, char*argv[ ] )
{
int pid;
int child_status;
signal(SIGCHLD, signal_handler); //子程序退出時所發訊號
pid = fork(); //建立子程序,使之讀取管道資料
int i =0;
switch(pid){
case-1:
printf("fork error");
exit( 1 );
case0:
read_pipe();
exit( 0 );
default: //做它自己無聊的事
for(i;i<100;i++){
printf("%d ", i);
fflush( stdout );
sleep(2);
}
}
return0;
}
/* fifoW.c 負責向管道檔案中寫資料 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define FIFO_NAME "/tmp/myfifo2" //定義巨集,指向管道檔案位置
#define TEN_MEG ( 1024*1024*10 ) //檔案緩衝區最大值
int main( int argc, char* argv[ ] )
{
int res;
int c;
int pipe_fd;
int open_mode = O_WRONLY; //設定讀寫許可權
int bytes_send =0;
if( access( FIFO_NAME, F_OK ) ==-1 ) { //F_OK : 檢查是否有這個檔案; 類似還有檢查檔案可讀等,參見man中access中定義
res = mkfifo( FIFO_NAME, 0777 ); //建立管道檔案,檔案屬性為0777,root可讀寫
if( res !=0 ){ //管道檔案不可重名
printf( "Could not create fifo %s ", FIFO_NAME );
exit( 1 );
}
}
pipe_fd = open( FIFO_NAME, open_mode ); //開啟管道,並設定開啟許可權
if( pipe_fd !=-1 ){
while( (c = getchar( )) >0 ){
res = write( pipe_fd, &c, 1 ); //向管道中寫資料
if( res ==-1 ){
perror( "write error" );
close( pipe_fd );
exit( 1 );
管道分類: 根據程序的相互關係,可以分為:匿名管道與命名管道。
1 匿名管道:管道是父程序和子程序間,或是子程序與子程序間單向的通訊機制,即一個程序傳送資料到管道,另外一個程序從管道中讀出資料。如果需要雙向,或是多項通訊機制,則需要建立兩個活多個管道.
系統負責兩件事:一是寫入管道的資料和讀出管道的資料的順序是相同的,二是資料不會在管道中丟失,除非某個程序過早的退出.
建立管道函式為
int pipe(int pipe[2]); //其中pipe[0]是讀取資料的描述字,pipe[1]是寫資料的描述字
例項:
#include <
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void read_data( int pipes[ ] )
{
int c;
int rc;
close( pipes[ 1 ] ); //由於此函式只負責讀,因此將寫描述關閉(資源寶貴)
while( (rc = read(pipes[ 0 ], &c, 1)) >0 ){ //阻塞,等待從管道讀取資料
putchar( c );
}
exit( 0 );
}
void write_data( int pipes[ ] )
{
int c;
int rc;
close( pipes[ 0 ] ); //關閉讀描述字
while( (c=getchar()) >0 ){
rc = write( pipes[ 1 ], &c, 1 ); //寫入管道
if( rc ==-1 ){
perror ("Parent: write");
close( pipes[
exit( 1 );
}
}
close( pipes[ 1 ] );
exit( 0 );
}
int main( int argc, char*argv[ ] )
{
int pipes[ 2 ];
pid_t pid;
int rc;
rc = pipe( pipes ); //建立管道
if( rc ==-1 ){
perror( "pipes" );
exit( 1 );
}
pid = fork( );
switch( pid ){
case-1:
perror( "fork" );
exit( 1 );
case0:
read_data( pipes ); //相同的pipes
default:
write_data( pipes ); //相同的pipes
}
return0;
}
上述匿名管道是與程序密切相關的。只有有關係的程序才能使用他們。至於兩個不相關的程序則需要用到有名字的管道,即命名管道。
2 命名管道:又稱FIFO (FIRST IN FIRST OUT). 它是檔案系統中的特殊檔案(注意是檔案哦,一般我們可以把它放在/tmp/xxxx裡). 不同的程序開啟相同的命名管道實現類似匿名管道的資料通訊。
ps: Unix/Linux 檔案系統:包括普通檔案,檔案目錄,與特殊檔案(FIFO是其中之一),FIFO檔案像普通檔案一樣,也有讀寫開啟等常用功能。
管道檔案刪除: 程式中可使用unlink()
接觸管道讀寫阻塞: 使用fcntl()
例項:先編譯執行fifoW.c , 再編譯執行fifoW.c fifoR的子程序接受管道資料,fifoW負責寫
/* fifoR.c 負責從管道檔案中讀取資料 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#define FIFO_NAME "/tmp/myfifo2" //定義巨集,指向管道檔案的位置
void read_pipe(){ //子程序, 處理從管道中讀資料
int pipe_fd;
int res;
int c;
int open_mode = O_RDONLY; //設定許可權,為只讀
pipe_fd = open( FIFO_NAME, open_mode ); //開啟管道檔案,並設定開啟許可權,返回int
if( pipe_fd!=-1 ){
while(1){
while( (res = read( pipe_fd, &c, 1 )) >0 ){ //從管道讀資料
putchar( c );
}
fflush( stdout );
}
}else{
exit( 1 );
}
close(pipe_fd);
}
void signal_handler( int n){ //受到子程序退出訊號,結束子程序
int child_status;
wait( &child_status );
printf( "child exited. " );
}
int main( int argc, char*argv[ ] )
{
int pid;
int child_status;
signal(SIGCHLD, signal_handler); //子程序退出時所發訊號
pid = fork(); //建立子程序,使之讀取管道資料
int i =0;
switch(pid){
case-1:
printf("fork error");
exit( 1 );
case0:
read_pipe();
exit( 0 );
default: //做它自己無聊的事
for(i;i<100;i++){
printf("%d ", i);
fflush( stdout );
sleep(2);
}
}
return0;
}
/* fifoW.c 負責向管道檔案中寫資料 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define FIFO_NAME "/tmp/myfifo2" //定義巨集,指向管道檔案位置
#define TEN_MEG ( 1024*1024*10 ) //檔案緩衝區最大值
int main( int argc, char* argv[ ] )
{
int res;
int c;
int pipe_fd;
int open_mode = O_WRONLY; //設定讀寫許可權
int bytes_send =0;
if( access( FIFO_NAME, F_OK ) ==-1 ) { //F_OK : 檢查是否有這個檔案; 類似還有檢查檔案可讀等,參見man中access中定義
res = mkfifo( FIFO_NAME, 0777 ); //建立管道檔案,檔案屬性為0777,root可讀寫
if( res !=0 ){ //管道檔案不可重名
printf( "Could not create fifo %s ", FIFO_NAME );
exit( 1 );
}
}
pipe_fd = open( FIFO_NAME, open_mode ); //開啟管道,並設定開啟許可權
if( pipe_fd !=-1 ){
while( (c = getchar( )) >0 ){
res = write( pipe_fd, &c, 1 ); //向管道中寫資料
if( res ==-1 ){
perror( "write error" );
close( pipe_fd );
exit( 1 );