1. 程式人生 > >《Linux程式設計》——程序間通訊:管道

《Linux程式設計》——程序間通訊:管道

一、管道

 1、管道:當從一個程序連結資料到另一個程序時,我們使用術語管道。通常把一個程序的輸出通過管道連線到另一個程序的輸入。

 2、程序管道

   1)、popen函式

         #include<stdio.h>

         FILE  *popen(const  char  *cpmmand,  const  char  *popen);

       I、popen函式允許一個程式將另一個程式作為新程序來啟動,並可以傳遞資料給它或者通過它接受資料。command字串是要執行的程式名和相應的函式。popen_mode必

           須是“r”或者“w”。

       II、每個popen呼叫都必須指定“r”或“w”,在popen函式的標準實踐中不支援任何其他選項。這意味著我怕們不能呼叫另一個程式並同時對它進行讀寫操作。popen函式在失敗時

            返回一個空指標。

    2)、pclose函式

         #include<stdio.h>

         int  pclose(FILE  *stream_to_close);

       I、用popen啟動的程序結束時,我們可以用pclose函式關閉與之關聯的檔案流。pclose只在popen啟動的程序結束後才返回。如果呼叫pclose時它任然運作,pclose呼叫

           將等待該程序的結束。

      II、pclose呼叫的返回值通常是它所關閉的檔案流所在程序的退出碼。如果呼叫程序在呼叫pclose之間執行了一個wait語句,被呼叫程序的退出狀態就會丟失,因為被呼叫進

            程已經結束。此時pclose將返回-1並設定errno為ECHILD。

 3、將輸出送往popen(程式碼P445-446)

 4、傳遞更多資料(程式碼P446-447)

 5、popen函式的實現(程式碼P448)

 6、pipe呼叫

     #include<unistd.h>

     int  pipe(int  file_descriptor[2]);

    I、此函式在兩個程式之間傳遞資料不需要啟動一個shell來解釋請求命令。它還提供了對讀寫資料的更多控制。

    II、此函式的引數是一個由兩個引數型別的檔案描述符組成的陣列的指標。該函式在陣列中填上兩個新的檔案描述符後返回0,如果失敗則返回-1並設定errno來表明錯誤的原

          因。兩個返回的檔案描述符以一種特殊的方式連線起來。寫到file_descriptor[1]的所有資料都可以從file_descriptor[0]都出來。資料基於先進先出的原則。

二、父程序與子程序

 1、程式碼——資料消費者和資料生產者(P452-453)

 2、管道關閉後讀操作

 3、把管道用作標準輸入和標準輸出

   1)、用管道連線兩個程序更簡潔的方法:把其中一個管道檔案描述符設定為一個已知值,一般是標準輸入0或標準輸出1。這樣做我們可以呼叫程式,即那些不需要以檔案描

             述 符為引數的程式。

   2)、#incldue<unistd.h>

             int  dup(int  file_descriptor);

             int  dup2(int  file_descriptor_one,  int  file_descriptor_two);

           I、dup呼叫的目的是開啟一個新的檔案描述符。它與open呼叫的區別是,dup呼叫建立的新檔案描述符與作為它的引數的那個已有檔案描述符指向同一個檔案(或管

               道)。

         II、對於dup2函式來說,新的檔案描述符總是取最小的可用值。而對於dup2來說,它所建立的新檔案描述符或者與引數file_descriptor_two相同。

         III、dup實現在兩個程序傳遞資料的方式:標準輸入的檔案描述符總是0,而dup返回的新的檔案描述符又總是使用最小可用的數字。

三、命名管道:FIFO

     #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_FIFO,  (dev_t)  0);

     I、與mknod命令一樣,我們可以是mknod函式簡歷許多特殊型別的檔案。要用mknod函式建立一個可移植的命名管道惟一方法是使用一個dev_t型別的值0,並將檔案訪問模

         式與S_FIFO按位與或

 1、訪問FIFO檔案(P458實驗)

 2、使用open開啟FIFO檔案

   1)、開啟FIFO的一個主要限制是:程式不能以O_RDWR模式開啟FIFO檔案進行讀寫操作。通常使用FIFO只是為了單向傳遞資料,所以沒有必要使用O_RDWR模式。

   2)、開啟FIFO檔案和開啟普通檔案的另一個區別是,對open_flag(open函式的第二個引數)的O_NONBLOCK選項的用法。使用這個選項不僅改變open呼叫處理方式,還

            會改變對這次open呼叫返回的檔案描述符進行的讀寫請求的處理方式。

   3)、O_RDONLY、O_WRONLY和O_NONBLOCK標誌四種合法的組合方式:

          I、open(const  char  *path,  O_RDONLY);

               在這種情況下,open呼叫劍阻塞,除非有一個程序以寫方式開啟同一個FIFO,否則它不會返回。

          II、open(const  char  *path,  O_RDONLY | O_NONBLOCK);

                即使沒有其它程序以寫方式開啟FIFO,這個open呼叫也將成功並立刻返回。

          III、open(const  char  *path,  O_WRONLY);

                 在這種情況下,open呼叫劍阻塞,除非有一個程序以讀方式開啟同一個FIFO,否則它不會返回。

          IV、open(const  char  *path,  O_WRONLY | O_NONMLOCK);

                 此函式呼叫總是立刻返回,但如果沒有程序以讀方式開啟FIFO檔案,open呼叫將返回一個錯誤-1並且FIFO也不會被開啟。如果有一個程序以讀方式開啟FIFO檔案,我

                 們可以通過它返回的檔案描述符對這個FIFO檔案進行寫操作。

   4)、不帶O_NONBLOCK標誌的O_RDONLY和O_WRONLY。

   5)、帶O_NONBLOCK標誌的O_RDONLY和不帶該標識的O_WRONLY。

   6)、對FIFO進行讀寫操作

         使用O_NONBLOCK模式會影響到對FIFO的read和write呼叫:

         I、對一個空的、阻塞的FIFO(既沒有用O_NONBLOCK標誌開啟)的read呼叫將等待,直到資料可以讀時才繼續執行。與此相反,對一個空的非阻塞的FIFO的read呼叫將

              立刻返回0位元組。

         II、對一個滿的、阻塞的FIFO的write呼叫將等待,直到資料可以被寫入時才繼續執行。如果FIFO不能接收所有寫入的資料,它會按下面的規則執行:

               *如果請求寫入的資料的長度小於等於PIPE_BUF位元組,呼叫失敗,資料不能寫入。

              *如果請求寫入的資料的長度小於PIPE_BUF位元組,將寫入部分資料,返回實際寫入的位元組數,返回值也可能是0。

   7)、系統對任一時刻在一個FIFO中可以存在到的資料長度是有限制的。它由#define PIPE_BUF語句定義,通常可以在標頭檔案limit.h中找到。

 3、高階主題:使用FIFO的客戶/伺服器應用程式(程式碼465-467)