IPC(进程间通信):
1、为什么需要通信:因为进程间都是独立的运行空间(内存空间),所。以不能进程间不能直接通信。
2、通信方式:
1、管道:
匿名管道:
命名管道:
2、信号:
3、共享内存:
4、消息队列:
5、Socket:
匿名管道
“有关系”的进程之间通信(父子进程)
1、创建管道:
#include <unistd.h>
int pipe(int pipefd[2]);
形参:
pipefd[2]:存储的是文件描述符,其中pipefd[0]--读端,pipefd[1]---写端
返回值:
失败-1,成功0
PS:
1、单向管道,只能一端读,一端写。
2、若某进程同时读写此管道,该管道直接破裂。
3、是一个存放在内存中一个数据结构算法,所以一当进程关闭,此管道丢失败。
4、匿名进程只能应用于关系进程(父子关系)
分析:
父子进程同时保持打开
1、父进程,(已经将写端关闭)保持读端打开;子进程,(已经将读端关闭),保持写端打开,若子进程不写入消息时,父进程当读取管道时,因为管道没有内容则阻塞等待子进程送入消息。
2、父进程,(已经将写端关闭)保持读端打开;子进程,(已经将读端关闭),保持写端打开,若父进程不读取消息,子进程一直写入消息时,若管道为满,子进程会被阻塞等待父进程读取出消息。
父子进程关闭读写端时
3、父进程,(已经将写端关闭)保持读端打开,子进程,(已经将读端关闭),关闭写端,此时,(管道破裂)父进程不会一直等待,将管道中剩余内容读取完成后,就返回0,不再阻塞。
4、父进程,(已经将写端关闭)关闭读端,子进程,(已经将读端关闭),保持写端打开,此时,(管道破裂)子进程写入内容时会产生一种信号,此时子进程直接退出(信号)
#include<stdio.h>
#include<sys/wait.h>
void main()
{
//在创建子进程之间创建
int fd[2];
if(pipe(fd)<0)
{
perror("pipe fail");
return ;
}
//printf("%d %d\n",fd[0],fd[1]);//fd[0]=3 fd[1]=4
//创建子进程
int pid=fork();
if(pid>0)//父进程:读取信息
{
//关闭写入
close(fd[1]);
//读取
/*sleep(10);
char buf[100]="";
while(read(fd[0],buf,99)>0)
{
printf("收到:%s\n",buf);
}
*/
close(fd[0]);//关闭读端
sleep(1);
//等待子进程
wait(NULL);
//关闭读取
close(fd[0]);
}
else if(pid==0)//子进程:发送信息
{
//关闭读
close(fd[0]);
//写入一句话:
/*
printf("子进程阻塞3秒,再写入\n");
sleep(3);
int i=0;
while(1)
{
i++;
write(fd[1],"hello father",13);
printf("子进程一直写入消息 %d\n",i);
}
*/
printf("子进程阻塞3秒,直接关闭\n");
sleep(2);
int i=write(fd[1],"hello father",13);
printf("写内容为%d\n",i);
//关闭
close(fd[1]);
}
else
{
perror("fork fail");
}
}
命名管道:
是一个(FIFO)特殊的文件(路径+文件名)
1、特点:
1、没有关系的进程之间也可以通信
2、FIFO(管道)总是按照先进先出的原则工作,第一个被写入数据首先从管道中读取(底层是通过网络接口)
3、双方没有关闭
无数据可读:
read调用会被阻塞,直到有数据来为止(阻塞模式)
read调用时会返回-1,errno位置为EAGAIN(非阻塞模式)
管道满:
write调用时会被阻塞,直到进程读走数据(阻塞模式)
write调用时返回-1,errno值置为EAGAIN(非阻塞模式)
如果所有写端已经关闭,read返回0
如果所有读端关闭,write操作会产生信号SIGPIPE信号
2、创建管道:
int mkfifo(const char *pathname, mode_t mode);
形参:
pathname:路径
mode:权限
返回值:
失败-1 errno=EEXIST 文件存在则导致创建失败
成功0
fifo_send
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<errno.h>
void main()
{
//创建命名管道
int res=mkfifo("./mypipe",0644);
if(res<0&& errno!=EEXIST)
{
perror("make fail");
return;
}
//操作文件:
//1、打开文件
int fd=open("./mypipe",O_WRONLY);
if(fd<0)
{
perror("open fail");
return;
}
//2、操作(写/读)
char buf[100]="";
while(1)
{
printf("请输入:");
scanf("%s",buf);//阻塞
//向管道文件写入内容
write(fd,buf,strlen(buf));
}
//3、关闭文件
close(fd);
}
fifo_recv
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main()
{
//1、打开
int fd=open("./mypipe",O_RDONLY);
if(fd<0)
{
perror("open fail \n");
return;
}
//2读取
char buf[100]="1234o";//5 1234
int ilen=0;
while((ilen=read(fd,buf,99))>0)
{
buf[ilen]='\0';
printf("收到:%s\n",buf);
}
//3关闭
close(fd);
}
执行:
gcc fifo_recv.c -o recv
gcc fifo_send.c -o send
用两个终端分别打开recv和send可以进行单向通信,一个读一个写