管道是進程間通信一種基本的的一種方式,管道又分爲兩種,匿名管道和命名管道,先說匿名管道
匿名管道(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 }
650) this.width=650;" src="http://s4.51cto.com/wyfs02/M01/7E/D6/wKiom1cJ7rjRpRR3AABHfYoycKg849.png" title="無標題.png" alt="wKiom1cJ7rjRpRR3AABHfYoycKg849.png" />輸出救過如左圖顯示,信號量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 }
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M01/7E/D3/wKioL1cJ-p6Rf0q7AAAlvJq_z3w875.png" title="無標題.png" alt="wKioL1cJ-p6Rf0q7AAAlvJq_z3w875.png" />在我的運行環境下(虛擬機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來創建。
server.c
#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 }
client
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 }
本文出自 “痕跡” 博客,請務必保留此出處http://wpfbcr.blog.51cto.com/10696766/1762380