管道是一種兩個進程間進行單向通信的機制。因為管道傳遞數(shù)據(jù)的單向性,管道又稱為半雙工管道。管道的這一特點決定了器使用的局限性。管道是Linux支持的最初Unix IPC形式之一,具有以下特點:
*** 數(shù)據(jù)只能由一個進程流向另一個進程(其中一個讀管道,一個寫管道);如果要進行雙工通信,需要建 立兩個管道。 *** 管道只能用于父子進程或者兄弟進程間通信。,也就是說管道只能用于具有親緣關系的進程間通信。
除了以上局限性,管道還有其他一些不足,如管道沒有名字(匿名管道),管道的緩沖區(qū)大小是受限制的。管道所傳輸?shù)氖菬o格式的字節(jié)流。這就需要管道輸入方和輸出方事先約定好數(shù)據(jù)格式。雖然有那么多不足,但對于一些簡單的進程間通信,管道還是完全可以勝任的。 使用管道進行通信時,兩端的進程向管道讀寫數(shù)據(jù)是通過創(chuàng)建管道時,系統(tǒng)設置的文件描述符進行的。從本質上說,管道也是一種文件,但它又和一般的文件有所不同,可以克服使用文件進行通信的兩個問題,這個文件只存在內存中。 通過管道通信的兩個進程,一個進程向管道寫數(shù)據(jù),另外一個從中讀數(shù)據(jù)。寫入的數(shù)據(jù)每次都添加到管道緩沖區(qū)的末尾,讀數(shù)據(jù)的時候都是從緩沖區(qū)的頭部讀出數(shù)據(jù)的。
#include <unistd.h>
int pipe(int pipefd[2]);
(匿名)管道兩端分別用描述符pipefd[0]及pipefd[1]來描述。需要注意的是,管道兩端的任務是固定的,一端只能用于讀,有描述符pipefd[0]表示,稱其為管道讀端;另一端只能用于寫,由描述符pipe[1]來表示,稱其為管道寫端。 該函數(shù)創(chuàng)建的管道的兩端處于一個進程中間,在實際應用中沒有太大意義,因此,一個進程在由pipe()創(chuàng)建管道后,一般再fork一個子進程,然后通過管道實現(xiàn)父子進程間的通信。在此不再作多介紹,下面看看有名管道吧。 管道的一個不足之處就是沒有名字,因此,只能用于具有親緣關系的進程間通信,在有名管道(name pipe或FIFO)提出后,該限制得到了解決。FIFO不同與管道之處在與她提供一個路徑名與之關聯(lián),以FIFO的文件形式存儲在文件系統(tǒng)中。有名管道是一個設備文件,因此,即使進程與創(chuàng)建FIFO的進程不存在親緣關系,只要可以訪問該路徑,就能夠通過FIFO相互通信了。值得注意的是FIFO(First In First Out)總是按照先進先出的原則工作,第一個被寫入的數(shù)據(jù)首先從管道中讀出。 在Linux中我們經常使用管道重定向數(shù)據(jù)。比如: 
下面介紹一下創(chuàng)建有名管道的系統(tǒng)調用,有兩個,mknod和mkfifo


#include <sys/types.h> #include <sys/stat.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);
int mkfifo( const char *pathname, mode_t mode ); 函數(shù)mknod參數(shù)中pathname為創(chuàng)建有名管道的全路徑名,mode為創(chuàng)建有名管道的模式,指明其存取權限;dev為設備值,該值取決于文件創(chuàng)建的種類,它只在創(chuàng)建設備文件是才會用到。這兩個函數(shù)調用成功都返回0,否則返回-1. 讀寫有名管道:#include <unistd.h> ssize_t read (int fd , void * buf , size_t nbytes) ssize_t write (int fd , void * buf , size_t nbytes) 接下來給大家演示一下通過有名管道通信的聊天程序。。。 - // 李四.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <errno.h>
- #define FIFO_READ "writefifo" //另外一個程序只要把本程序
- #define FIFO_WRITE "readfifo" //拷貝一份然后調換這兩個宏即可
- #define BUF_SIZE 1024
- int left = 0;
- void *read_buf()
- {
- int rfd = -1;
- char buf[BUF_SIZE] = { '\0' };
- int i;
- printf("等待對方……\n");
- while ((rfd = open(FIFO_READ, O_RDONLY)) == -1) {
- sleep(1);
- }
- while (left != 1) {
- //printf("i=%d ",i++);
- int len = read(rfd, buf, BUF_SIZE);
- if (len > 0) {
- buf[len] = '\0';
-
- if(strcmp(buf,"不理你了") == 0){
- printf("\n對方已經走開!\n");
- left = 1;
- break;
- // exit(0);
- }
- for(i = 0; i < strlen("我:"); i++)
- printf("\b");
- printf("對方:%s\n", buf);
- printf("我:");
- fflush(stdout);
- }
- }
-
- close(rfd);
- return NULL;
- }
- void *write_to()
- {
- int wfd;
- char buf[BUF_SIZE];
- int len;
- umask(0);
- if (mkfifo(FIFO_WRITE, S_IFIFO | 0666)) {
- printf("Can't create FIFO %s because %s", FIFO_WRITE,
- strerror(errno));
- exit(1);
- }
- umask(0);
- wfd = open(FIFO_WRITE, O_WRONLY);
- if (wfd == -1) {
- printf("open FIFO %s error: %s", FIFO_WRITE, strerror(errno));
- exit(1);
- }
- while (left != 1) {
- printf("我: ");
- fgets(buf, BUF_SIZE, stdin);
- buf[strlen(buf) - 1] = '\0';
- if (strcmp(buf, "不理你了") == 0 || left == 1) {
- write(wfd, buf, strlen(buf));//通知對方
- close(wfd);
- unlink(FIFO_WRITE);
- exit(0);
- }
- write(wfd, buf, strlen(buf));
- fflush(stdin);
- }
- }
- int main(int argc, char *argv[])
- {
- pthread_t thIDr, thIDw;
-
- pthread_create(&thIDr, NULL,(void *)read_buf, NULL);
- pthread_create(&thIDw, NULL,(void *)write_to, NULL);
- pthread_join(thIDr, NULL);
- pthread_join(thIDw, NULL);
- return 0;
- }
學以置用,呵呵,效果如下:

注:本博客的文章除注明有“轉載”字樣的外,均為原創(chuàng),歡迎轉載,請注明文字出處,謝謝!
|