1. 程式人生 > >嘗試linux下c程式設計之管道

嘗試linux下c程式設計之管道

今天試了下管道,感覺挺有意思的~ 現在才發現,原來程序也有這麼多的功能可以實現。

管道分類: 根據程序的相互關係,可以分為:匿名管道與命名管道。

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 );