进程间通信目的:
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享同样的资源
- 通知事件:一个进程需要向另一个或一组进程发送信息,通知它们发生了某种事件
- 进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及 时知道它的状态改变
常见的几种通信方式
管道:Linux进程间通信的几种主要手段,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此, 有名管道允许无亲缘关系进程间的通信
- 匿名管道:用于具有亲缘关系进程间的通信
匿名管道调用函数:
int pipe(int fd[2]);
fd:文件描述符数组,f[0]表示读端,f[1]表示写端
因为匿名管道只能用于具有亲缘关系进程间的通信,所有我们创建一对父子进程来看它的作用
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int pipefd[2];
if(pipe(pipefd)==-1)
perror("make pipe");
pid_t pid;
pid = fork();
if(pid==-1)
perror("fork");
else if(pid == 0)
{
close(pipefd[0]);
write(pipefd[1],"hello",5);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
char buf[10]= {0};
read(pipefd[0],buf,10);
printf("buf = %s\n",buf);
return 0;
}
我们创建了一个管道,在子进程中将读端关闭,向管道内写入内容,在父进程中将写端关闭,从管道中读出内容,这样我们就将两个进程联系了起来,且各自不影响对方的行为,由结果也能看出,两个进程的确互不干扰完成了自己的任务。
- 命名管道:命名管道突破了匿名管道亲缘关系进程间通信的限制,在非亲缘关系进程间也可以使用
命名管道创建
命名管道可以从命令行上创建,为如下指令:
$ mkfifo filename
也可以从程序里创建,相关函数为:
int mkfifo(const char* filename,mode_t mode);
我们可以建立一个命名管道用于两个进程间通信体会一下它的作用
int main()
{
if(mkfifo("mypipe",0644)<0)
{perror("make pipe");}
int rfd = open("mypipe",O_RDONLY);
if(rfd<0)
perror("open");
char buf[1024];
while(1)
{
buf[0]=0;
printf("Please wait ..\n");
size_t s = read(rfd,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1] = 0;
printf("client say# %s\n",buf);
}
else if(s==0)
{
printf("cilent quit,exit now\n");
exit(EXIT_SUCCESS);
}
else
perror("read");
}
close(rfd);
return 0;
}
int main()
{
int wfd = open("mypipe",O_WRONLY);
if(wfd<0)
perror("open");
char buf[1024];
while(1)
{
buf[0]=0;
printf("Pleas Enter# ");
fflush(stdout);
ssize_t s = read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
write(wfd,buf,strlen(buf));
}
else if(s<=0)
perror("read");
}
return 0;
}
运行代码后,启用两个终端,一个终端输入内容可以在另外一个显示出来,证明管道的确构建成功了。