一.进程间通信的背景及目的
1)背景
进程间具有独立性,直接交互并不方便,内核提供一个公共资源,多个进程通过这个公共资源进行交互
2)目的
数据传输,资源共享,通知事件,进程控制
二.进程间通信的几种方式
管道,消息队列,共享内存,信号量,信号
三.管道
1.管道分类:匿名管道和命名管道
2.管道的概念:把从一个进程连接到另一个进程的一个数据流称为一个“管道”。
3.本质:通过文件描述符来管理管道,也是内核提供的一段内存(队列)
4.匿名管道
a)头文件:#include <unistd.h>
b) 函数原型: int pipe(int fd[2])
c) 参数:fd文件描述符数组,其中fd[0]表示读端(0像嘴巴),fd[1]表示写端(1像笔)
d) 返回值:成功返回0,失败返回错误代码
e)调用过程:(要边读编写)
f)写一个小栗子:
从标准输入读数据,写进管道,读取管道,写到标准输出上
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int main(void){
5 int fd[2];
6 if(pipe(fd)==0){ //成功
7 char buf[1024]={0};
8 int size=sizeof(buf);
9 int len;
10 while(fgets(buf,size,stdin)){
11 len=strlen(buf);
12 if(write(fd[1],buf,len)!=len)
13 break;
14 memset(buf,0x00,size);
15 if(read(fd[0],buf,size)==-1)
16 break;
17 if(write(1,buf,len)!=len)
18 break;
19 }
20 }else{
21 perror("pipe");
22 return -1;
23 }
24 return 0;
25 }
g)父子进程可以同时调用一个管道
h)管道的限制:
1)只能在有亲缘关系的进程间使用。
2)管道是半双工,只能由一端向另一端,需要双方通信时,需要建立两个管道。
3)管道的生命周期随进程
4)内核会对管道进行同步和互斥。
5)管道提供流式服务
i)父子进程同时使用一个管道,父进程读,子进程写
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main(void){
6 int fds[2];
7 if(pipe(fds)==-1){
8 perror("pipe");
9 return -1;
10 }
11 int pid=fork();
12 if(pid==-1){
13 perror("fork");
14 return -1;
15 }
16 if(pid==0){ //child answer for pipe write
17 close(fds[0]);
18 char *buf="hello-world";
19 write(fds[1],buf,strlen(buf));
20 close(fds[1]);
21 }else{ //father answer for read
22 close(fds[1]);
23 char buf[1024]={0};
24 read(fds[0],buf,sizeof(buf));
25 printf("%s\n",buf);
26 close(fds[0]);
27 }
28 return 0;
29 }
5.命名管道
a)由来:由于匿名管道必须有共同的祖先才能进行通信,如果我们想在不相关的进程之间通信,可以使用FIFO文件来完成,它被叫做命名管道。(创建的文件就是常说的管道文件)
b)创建一个命名管道:
1.使用命令行mkfifo filename
2.使用函数mkfifo
·)头文件: #include <sys/types.h>
#include <sys/stat.h>
·)函数原型:int mkfifo(const char *pathname, mode_t mode);
·)参数:pathname文文件名,mode是文件的权限
c)使用命名管道进行进程间通信
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <sys/types.h>
6
7 //sever answer for read
8 int main(void){
9 mkfifo("letter.p",0644);
10 int fd=open("letter.p",O_RDONLY);
11 if(fd==-1) perror("open"),exit(1);
12
13 char buf[1024]={0};
14 while(1){
15 memset(buf,0x00,sizeof(buf));
16 int ret=read(fd,buf,sizeof(buf)-1);
17 if(ret==-1){
18 perror("read");
19 return -1;
20
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6
7 int main(void){
8 int fd=open("letter.p",O_WRONLY);
9 if(fd==-1) perror("open"),exit(1);
10
11 char buf[1024]={0};
12 while(1){
13 memset(buf,0x00,sizeof(buf));
14 printf("Client Enter#");
15 fflush(stdout);
16 scanf("%s",buf);
17 write(fd,buf,strlen(buf));
18 }
19 close(fd);
20 return 0;
21 }
d)命名管道的实现本质
连接内核缓存,磁盘需要挂载到某个文件时才可用。假如A和B通过管道文件进行通信,管道文件的硬链接数为3,其实是A和B通过管道找到内核缓存,并挂载到内核缓存上,删除了管道文件进程AB仍继续,只是文件名删除了,文件中没有任何东西,只是连接到内核缓存。
6.匿名管道和命名管道的区别
1)匿名管道由pipe函数创建并打开
2)命名管道由mkfifo函数创建,用open打开
3)只有创建和打开的方式不同,之后完成同样的事情。
·