管道是程序間通信一種基本的的一種方式,管道又分為兩種,匿名管道和命名管道,先說匿名管道
匿名管道(pipe)
#include <unistd.h>
int pipe(int filedes[2]);
調用pipe時會在核心中開辟一個緩沖區,使用時fileds[0]為輸出端,fileds[1]為寫入端口,調用成功時傳回0,失敗時傳回-1;
pipe的特點:
1:它隻能在有血緣關系的程序間進行通信。
2:它隻能進行單項通信,一個程序讀,另一個隻能寫。
3:它是一種流式服務。
4:它的生命周期跟随程序的生命周期。
pipe在使用的時候有四種特殊情況,
1>(代碼如下):
如果所有指向管道寫端的檔案描述符都關閉了(管道寫端的引用計數等于0),而仍然有
程序 從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會傳回0,就像
讀檔案末一樣。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<sys/types.h>
5 #include<string.h>
6 int main()
7 {
8 int status=0;
9 int _pipe_id[2];
10 if(pipe(_pipe_id)<0)
11 {
12 perror("pipe");
13 exit(1);
14 }
15 pid_t id=fork();
16 if(id<0)
17 {
18 perror("fork");
19 }
20 else if(id==0)
21 {
22 close(_pipe_id[0]);
23 char my_buf[]="hello world";
24 int count=10;
25 while(count--){
26 //if(count<5)
27 // {
28 write(_pipe_id[1],my_buf,strlen(my_buf));
29 // }
30 sleep(1);
31 }
32 close(_pipe_id[1]);
33 }
34 else
35 {
36 close(_pipe_id[1]);
37 char my_buf[1024];
38 int count=100;
39 while(count--)
40 {
41 memset(my_buf,'\0',sizeof(my_buf));
42 ssize_t size= read(_pipe_id[0],my_buf,sizeof(my_buf));
43 printf("%d,%s\n",size,my_buf);
44 }
45 pid_t _wait_pid=waitpid(id,NULL,0);
46 if(_wait_pid<0)
47 {
48 return 1;
49 }
50 }
51 return 0;
52 }
輸出結果就是每隔一秒讀取子程序寫進管道的字元串,read不停地傳回零,然後結束 2> (代碼将上面的代碼的注釋去掉) 如果有指向管道寫端的檔案描述符沒關閉(管道寫端的引用計數大于0),而持有管道寫
端的 程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的數
據都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料并傳回。
3>(代碼如下,将上面的父程序代碼改成這樣)
如果所有指向管道讀端的檔案描述符都關閉了(管道讀端的引用計數等于0),這時有進
程向管道的寫端write,那麼該程序會收到信号SIGPIPE(讀端關閉後,連續有兩條寫入的指令則會傳回這個異常信号量),通常會導緻程序異常終止。
38 int count=5;
39 while(count--)
40 {
41 memset(my_buf,'\0',sizeof(my_buf));
42 ssize_t size= read(_pipe_id[0],my_buf,sizeof(my_buf));
43 printf("%d,%s\n",size,my_buf);
44 }
45 close(_pipe_id[0]);
46 pid_t _wait_pid=waitpid(id,&status,0);
47 printf("status=%d\n",status&0xff);
48 }
輸出救過如左圖顯示,信号量13就是SIGPIPE。
4>
如果有指向管道讀端的檔案描述符沒關閉(管道讀端的引用計數大于0),而持有管道讀
端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫入資料并傳回
子程序如下
24 int count=0;
25 while(1){
26 count++;
27 ssize_t size=write(_pipe_id[1],my_buf,strlen(my_buf));
28 if(size>0)
29 {
30 printf("child%d\n",count); ;
31 }
32 else{
33 printf("child_count=%d,size=%d\n",count,size);
34 sleep(3);
35 }
36 }
37 }
父程序如下
38 else
39 {
40 sleep(1);
41 close(_pipe_id[1]);
42 char my_buf[1024];
43 int count=15;
44 while(count--)
45 {
46
47 memset(my_buf,'\0',sizeof(my_buf));
48 ssize_t size= read(_pipe_id[0],my_buf,sizeof(my_buf));
49 printf("%d,%s\n",size,my_buf);
50 sleep(5);
51 }
在我的運作環境下(虛拟機CentOS),一次最多向管道裡寫入了70kb的内容,而後當父程序讀取了資料才開始繼續存儲。
命名管道(FIFO) 因為匿名管道隻能在有血緣關系的程序間通信,是以又引入了命名管道,命名管道其實就是通過建立一個公共的雙方都能通路的檔案來使雙方進行通信,有兩種方法可以建立這種管道,一個是在程式中調用mknod或mkfifo函數建立一個命名管道,另外一個方法是在shell下互動的建立一個命名管道。#include <sys/types.h>
#include <sys/stat.h>
int mknod(const char *path,mode_t mod,dev_t dev);
int mkfifo(const char *path,mode_t mode);
函數參數第一個為路徑,第二個是權限,一般使用S_IFIFO|0666來建立。 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<string.h>
5 #include<error.h>
6 #include<fcntl.h>
7 #include<unistd.h>
8 #define _PATH_ "./.tmp_fifo"
9
10 int main()
11 {
12 umask(0);
13 if(mkfifo(_PATH_,0666|S_IFIFO)<0)
14 {
15 perror("mkfifo");
16 }
17 char my_buf[1024];
18 memset(my_buf,'\0',sizeof(my_buf));
19 int fd=open(_PATH_,O_WRONLY);
20
21 if(fd<0)
22 {
23 perror("open");
24 }
25
26 while(1)
27 {
28 printf("please write:");
29 fflush(stdout);
30 fgets(my_buf,sizeof(my_buf)-1,stdin);
31 int size=write(fd,my_buf,strlen(my_buf));
32 if(size<0)
33 {
34 printf("write error!\n");
35 break;
36 }
37 if(strncmp(my_buf,"quit",4)==0)
38 {
39 break;
40 }
41 }
42 close(fd);
43 return 0;
44 }
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<string.h>
5 #include<error.h>
6 #include<fcntl.h>
7 #include<unistd.h>
8
9 #define _PATH_ "./.tmp_fifo"
10
11 int main()
12 {
13 int fd=open(_PATH_,O_RDONLY);
14 if(fd<0)
15 {
16 perror("open");
17 }
18 char my_buf[1024];
19 memset(my_buf,'\0',sizeof(my_buf));
20 while(1)
21 {
22 int size=read(fd,my_buf,sizeof(my_buf)-1);
23 perror("open");
24 }
25
26 while(1)
27 {
28 printf("please write:");
29 fflush(stdout);
30 fgets(my_buf,sizeof(my_buf)-1,stdin);
31 int size=write(fd,my_buf,strlen(my_buf));
32 if(size<0)
33 {
34 printf("write error!\n");
35 break;
36 }
37 if(strncmp(my_buf,"quit",4)==0)
38 {
39 break;
40 }
41 }
42 close(fd);
43 return 0;
44 }