进程间通信(ipc):管道 信号量 共享内存 消息队列 套接字
管道文件:本身在磁盘中,打开文件以后会在内存中分配空间.(写入的数据存放在内存中)
有名管道和无名管道的区别:
有名管道可以在任意两个进程间通信
无名管道只能在父子进程间使用
管道通信方式:半双工
写入管道的数据在内存中
有名管道:(1)有名管道,如果一个进程以只写方式打开,进程会在open阻塞运行,直到另一个进程以只读方式打开;同理,一个进程以只读方式打开,进程也会在open阻塞运行,直到另一个进程以只写方式打开;因此当管道文件同时已读写方式打开才有意义。
(2)read端会阻塞运行,直到写端写入数据或者写端关闭。
有名管道:mkfifo,mkfifo();
无名管道:pipe();
有名管道
管道为空,读会阻塞
管到写满,写会阻塞
管道写端关闭,读端返回为0
管道读端关闭,写端写入数据异常
利用管道实现进程间通信
一个进程向管道文件写数据一个文件从管道中读数据
向管道中写数据
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main(){
int fdw=open("fifo",O_WRONLY);//只写方式打开管道文件
assert(fdw!=-1);
printf("fdw=%d\n",fdw);
while(1){
char buff[128]={0};
printf("input:\n");
fgets(buff,128,stdin);//从键盘读入字符串
if(strncmp(buff,"end",3)==0){//输入end是跳出循环,写端关闭
break;
}
write(fdw,buff,strlen(buff));//向管道文件中写数据
}
close(fdw);//关闭管道文件
exit(0);
}
从管道中读数据
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main(){
int fdr=open("fifo",O_RDONLY);//以只读方式打开管道文件
assert(fdr!=-1);
printf("fdr=%d\n",fdr);
while(1){
char buff[128]={0};
int n=read(fdr,buff,127);//从管道读数据并写到buff中
if(n==0){
break;
}
printf("buff=%s\n",buff);
}
close(fdr);//关闭管道文件
exit(0);
}
单独执行 读操作的进程和写操作的进程
可以看出a 和 b进程都没有执行。
因为,只有一个进程以读或者以写方式打开时会阻塞在open这块。只有两个进程分别以读或者以写方式打开时才会正常执行。
此时两个进程一起打开管道文件,一个写一个读(hello有换行是由于读入\n),进程才能正常执行。
管道写端关闭,读端返回0
写端关闭后,读端read返回值为0退出循环执行关闭文件。
管道读端关闭,写端写入数据触发异常。
关闭读端时,写端输入数据开始执行write时触发异常,此处通过发信号实现。
无名管道
int pipe(int pipefd[2]);
pipefd:用来存放PIPE的读写端描述符
pipe(fd) //fd[0]是读端口,fd[1]是写端口.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
#include<signal.h>
int main(){
int fd[2];
int res=pipe(fd); //创建无名管道
assert(res!=-1);
pid_t pid=fork();
assert(pid!=-1);
if(pid==0){//子进程负责读
close(fd[1]);//关闭写端
while(1){
char buff[128]={0};
int n=read(fd[0],buff,127);
if(n==0) break;//读端关闭read返回值为0,退出循环
printf("child buff=%s\n",buff);
}
close(fd[0]);//读完之后关闭读端
}else{//父进程负责写端
close(fd[0]);//关闭读端
while(1){
char buff[128]={0};
printf("input:");
fgets(buff,128,stdin);//从键盘获取数据
if(strncmp("end",buff,3)==0) break;//输入为end执行结束,跳出循环关闭写端
write(fd[1],buff,strlen(buff));
}
close(fd[1]);//关闭写端
}
exit(0);
}