細說linux IPC(六):pipe和FIFO

來源:互聯網
上載者:User

標籤:http   io   ar   os   使用   sp   for   檔案   資料   

在unix系統上最早的IPC形式為管道,管道的建立使用pipe函數:
  1. #include <unistd.h>  
  2.  int pipe(int pipefd[2]);  

該函數建立一個單向的管道,返回兩個描述符 pipefd[0],和pipefd[1],pipefd[0]用於讀操作,pipefd[1]用於寫操作。該函數一般應用在父子進程(有親緣關係的進 程)之間的通訊,先是一個進程建立管道,再fork出一個子進程,然後父子進程可以通過管道來實現通訊。
管道具有以下特點:
管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;
只能用於父子進程或者兄弟進程之間(具有親緣關係的進程);
單獨構成一種獨立的檔案系統:管道對於管道兩端的進程而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,而是自立門戶,單獨構成一種檔案系統,並且只存在與記憶體中。
資料的讀出和寫入:一個進程向管道中寫的內容被管道另一端的進程讀出。寫入的內容每次都添加在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。


函數pipe一般使用步驟如下:
1.pipe建立管道;
2.fork建立子進程;
3.父子進程分別關閉掉讀和寫(或寫和讀)描述符;
4.讀端在讀描述符上開始讀(或阻塞在讀上等待寫端完成寫),寫端開始寫,完成父子進程通訊過程。
一個簡單的通訊實現(來自linux man手冊的修改)
  1. #include <sys/wait.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <unistd.h>  
  5. #include <string.h>  
  6. #include <errno.h>  
  7.   
  8.   
  9. int main(int argc, char *argv[])  
  10. {  
  11.    int pipefd[2];  
  12.    pid_t cpid;  
  13.    char buf[128];  
  14.    int readlen;  
  15.   
  16.   
  17.    if (argc != 2) {  
  18.         fprintf(stderr, "Usage: %s <string>\n", argv[0]);  
  19.         return -1;  
  20.    }  
  21.    if (pipe(pipefd) < 0) {  
  22.        fprintf(stderr, "pipe: %s\n", strerror(errno));  
  23.        return -1;  
  24.    }  
  25.    cpid = fork();  
  26.    if (cpid < 0) {  
  27.        fprintf(stderr, "fork: %s\n", strerror(errno));  
  28.        return -1;  
  29.    }  
  30.    if (0 == cpid) { /* 子進程 */  
  31.        close(pipefd[1]); /* 子進程關閉寫端 */  
  32.        readlen = read(pipefd[0], buf, 128); //子進程阻塞在讀上,等待父進程寫  
  33.        if (readlen < 0) {  
  34.             fprintf(stderr, "read: %s\n", strerror(errno));  
  35.             return -1;  
  36.        }  
  37.        write(STDOUT_FILENO, buf, readlen);  
  38.        write(STDOUT_FILENO, "\n", 1);  
  39.        close(pipefd[0]); //讀完之後關閉讀描述符  
  40.        return 0;  
  41.    } else { /* 父進程 */  
  42.        close(pipefd[0]); /*父進程關閉沒用的讀端 */  
  43.        sleep(2);  
  44.        write(pipefd[1], argv[1], strlen(argv[1])); //父進程開始寫  
  45.        close(pipefd[1]); /* 父進程關閉寫描述符 */  
  46.        wait(NULL); /* 父進程等待子進程退出,回收子進程資源 */  
  47.        return 0;  
  48.    }  
  49. }  

運行時將列印命令列輸入參數,列印將在父進程睡眠2秒之後,子進程將阻塞在讀,直到父進程寫完資料,可見管道是有同步機制的,不需要自己添加同步機制。如果希望兩個進程雙向資料轉送,那麼需要建立兩個管道來實現。
管道最大的劣勢就是只能在擁有共同祖先進程的進程之間通訊,在無親緣關係的兩個進程之間沒有辦法使用,不過有名管道FIFO解決了這個問題。FIFO類似 於pipe,也是只能單向傳輸資料,不過和pipe不同的是他可以在無親緣關係的進程之間通訊,它提供一個路徑與之關聯,所以只要能訪問該路徑的進程都可 以建立起通訊,類似於前面的共用記憶體,都提供一個路徑與之關聯。
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. int mkfifo(const char *pathname, mode_t mode);  
pathname 為系統路徑名,mode為檔案許可權位,類似open函數第二個參數。
開啟或建立一個新的fifo是先調用mkfifo,當指定的pathname已存在fifo時,mkfifo返回EEXIST錯誤,此時再調用open函數。
下面來使用mkfifo實現一個無親緣關係進程間的雙向通訊,此時需要建立兩個fifo,分別用於讀寫。服務進程迴圈的讀並等待客戶進程寫,之後列印客戶進程傳來資料並向客戶進程返回資料;客戶進程向伺服器寫資料並等待讀取服務進程返回的資料。
server process:
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <errno.h>  
  4. #include <sys/stat.h>  
  5. #include <sys/types.h>  
  6. #include <fcntl.h>  
  7. #include "slnipc.h"  
  8. int main(int argc, const char *argv[])  
  9. {  
  10.     int rc;  
  11.     int wr_fd, rd_fd;  
  12.     char sendbuf[128];  
  13.     char recvbuf[128];  
  14.     rc = mkfifo(SLN_IPC_2SER_PATH, O_CREAT | O_EXCL); //建立服務進程讀的fifo  
  15.     if ((rc < 0 ) && (errno != EEXIST)) {  
  16.         fprintf(stderr, "mkfifo: %s\n", strerror(errno));  
  17.         return -1;  
  18.     }  
  19.     rc = mkfifo(SLN_IPC_2CLT_PATH, O_CREAT | O_EXCL); //建立服務進程寫的fifo  
  20.     if ((rc < 0 ) && (errno != EEXIST)) {  
  21.         fprintf(stderr, "mkfifo: %s\n", strerror(errno));  
  22.         return -1;  
  23.     }  
  24.     wr_fd = open(SLN_IPC_2CLT_PATH, O_RDWR, 0);  
  25.     if (wr_fd < 0) {  
  26.         fprintf(stderr, "open: %s\n", strerror(errno));  
  27.         return -1;  
  28.     }  
  29.     rd_fd = open(SLN_IPC_2SER_PATH, O_RDWR, 0);  
  30.     if (rd_fd < 0) {  
  31.         fprintf(stderr, "open: %s\n", strerror(errno));  
  32.         return -1;  
  33.     }  
  34.     for (;;) {  
  35.         rc = read(rd_fd, recvbuf, sizeof(recvbuf)); //迴圈等待接受客戶進程資料  
  36.         if (rc < 0) {  
  37.             fprintf(stderr, "read: %s\n", strerror(errno));  
  38.             continue;  
  39.         }  
  40.         printf("server recv: %s\n", recvbuf);  
  41.         snprintf(sendbuf, sizeof(sendbuf), "Hello, this is server!\n");  
  42.         rc = write(wr_fd, sendbuf, strlen(sendbuf));  
  43.         if (rc < 0) {  
  44.             fprintf(stderr, "write: %s\n", strerror(errno));  
  45.             continue;  
  46.         }  
  47.     }  
  48.     close(wr_fd);  
  49.     close(rd_fd);  
  50.     return 0;  
  51. }  

client process
  1. #include <stdio.h>  
  2. #include <sys/stat.h>  
  3. #include <sys/types.h>  
  4. #include <fcntl.h>  
  5. #include <string.h>  
  6. #include <errno.h>  
  7. #include "slnipc.h"  
  8. int main(int argc, const char *argv[])  
  9. {  
  10.     int rc;  
  11.     int rd_fd, wr_fd;  
  12.     char recvbuf[128];  
  13.     char sendbuf[128];  
  14.     if (argc != 2) {  
  15.         fprintf(stderr, "Usage: %s <string>\n", argv[0]);  
  16.         return -1;  
  17.     }  
  18.     snprintf(sendbuf, sizeof(sendbuf), "%s", argv[1]);  
  19.     wr_fd = open(SLN_IPC_2SER_PATH, O_RDWR, 0);  
  20.     if (wr_fd < 0) {  
  21.         fprintf(stderr, "open: %s\n", strerror(errno));  
  22.         return -1;  
  23.     }  
  24.     rd_fd = open(SLN_IPC_2CLT_PATH, O_RDWR, 0);  
  25.     if (rd_fd < 0) {  
  26.         fprintf(stderr, "open: %s\n", strerror(errno));  
  27.         return -1;  
  28.     }  
  29.     rc = write(wr_fd, sendbuf, strlen(sendbuf));  
  30.     if (rc < 0) {  
  31.         fprintf(stderr, "write: %s\n", strerror(errno));  
  32.         return -1;  
  33.     }  
  34.     rc = read(rd_fd, recvbuf, sizeof(recvbuf));  
  35.     if (rc < 0) {  
  36.         fprintf(stderr, "write: %s\n", strerror(errno));  
  37.         return -1;  
  38.     }  
  39.     printf("client read: %s\n", recvbuf);  
  40.     close(wr_fd);  
  41.     close(rd_fd);  
  42.     return 0;  
  43. }  

伺服器先啟動運行,之後運行用戶端,運行結果
  1. # ./server   
  2. server recv: hi,this is fifo client   
  3.   
  4.   
  5. # ./client "hi,this is fifo client"   
  6. client read: Hello, this is server!   


這裡有一些類似於socket實現處理序間通訊過程,只是fifo的讀寫描述符是兩個,socket的讀寫使用同一個描述符。fifo的出現克服了管道的只 能在有親緣關係的進程之間的通訊。和其他的處理序間通訊一直,fifo傳送的資料也是位元組流,需要自己定義協議格式來解析通訊的資料,可以使用socket 章節介紹的方式來實現的通訊協定。

本節源碼下載:

http://download.csdn.net/detail/gentleliu/8183027
  • 相關文章推薦:
  • 細說linux IPC(一):基於socket的處理序間通訊(上)
  • 細說linux IPC(二):基於socket的處理序間通訊(下)
  • 細說linux IPC(三):mmap系統調用共用記憶體
  • 本文來自:愛好Linux技術網
  • 本文連結:http://www.ahlinux.com/c/9591.html
 

細說linux IPC(六):pipe和FIFO

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.