通信方式分4大类:
管道通信:无名管道 有名管道
信号通信:发送 接收 和 处理
IPC通信:共享内存 消息队列 信号灯
socke 网络通信
用户空间 进程A <----无法通信----> 进程B
-----------------|--------------------------------------|--------------
| |
内核空间 |<-------------> 对象 <--------------->| ---------------------------------------------------------------------- //基于文件IO的思想
//open 打开或者创建一个文件,内核开辟一个buffer -->打开对象
//write 往buffer里面写
//read 从buffer读
//close 释放buffer
1. 进程间的管道通信
用户空间 进程A <----无法通信----> 进程B
-----------------|--------------------------------------|--------------
| |
内核空间 |<-------------> 管道 <--------------->| ---------------------------------------------------------------------- 管道文件时一个特殊的文件,由队列来实现
open --> pipe
管道中的东西读完了,就删除了、
管道中如果没有东西可读,就会 读堵塞
管道中如果写满了,就会写阻塞
1.1 无名管道
无名管道用于父子进程带有亲缘关系的进程
#include <unistd.h>
int pipe(int fildes[]); //创建
//文件描述符 filds[0]-read--出队 filds[1]-write--入队 write(); //写
read(); //读
close(fd[]);
close(fd[]); ------------------------------
fd[]write fd[]read
------------------------------
小例子
int main()
{
int fd[]; //pipe的2个文件描述符
int ret;
ret = pipe(fd); //创建管道
if(ret < ){
perror("pipe");
return -;
}
printf("fd[0] = %d, fd[1] = %d\n",fd[],fd[]);
return ;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h> int main(int argc, char const *argv[])
{
int fd[];
int ret;
const char *writebuf = "hello pipe";
char readbuf[] = {}; //1,创建pipe
ret = pipe(fd);
if(ret < )
{
perror("pipe");
return -;
}
printf("fd[0] = %d,fd[1] = %d\n",fd[],fd[]); //2.write
ret = write(fd[],writebuf,strlen(writebuf));
if(ret < ){
perror("write");
}
//2.read
ret = read(fd[],readbuf,);
if(ret < ){
perror("read");
return -;
} printf("read: %s\n",readbuf); //3.close
close(fd[]);
close(fd[]);
return ;
}
1.2 有名管道
对于无名管道,pipe要在fork之前创建,这样fork的时候,会将fd[0]和fd[1]拷贝,这样两个进程就使用的是同2个设备描述符,如果pipe在fork之后创建,那个2个进程就会分别创建1个管道,操作的不是同一个管道文件,就没办法实行通信。
也就是说,无名管道只能用于fork创建这样的父子进程, 如果无亲缘关系的进程,无名管道没办法进行通信,就只能使用有名管道。
有名管道 即创建一个带有文件inode节点的管道文件 p, 该文件不占有内存空间,仅有一个文件节点, 当该节点被open时,才占用内存空间。
mkfifo 只是在用户空间创建了一个管道文件,并非在内存空间创建管道,只有在open时,才在内存空间创建一个管道。
注,有名管道两端成对打开时才会开始执行
#include <sys/types.h>
#include <sys/stat.h> int mkfifo(const char *path, mode_t mode); //文件路径 文件权限
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h> int main(int argc, char const *argv[])
{
int ret; //0=ok -1=failes ret = mkfifo("./fifo",); //创建管道文件 路径+权限
if(ret < ){
perror("mkfifo");
return -;
}
return ;
}
例子
fifo.c 创建有名管道文件
lude <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h> int main(int argc, char const *argv[])
{
int ret; ret = mkfifo("./fifo",); //创建管道文件 路径+权限
if(ret < ){
perror("mkfifo");
return -;
}
return ;
}
first.c 进程1
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h> int main(int argc, char const *argv[])
{
int fd;
int process_int = ; fd = open("./fifo",O_WRONLY); //注,有名管道两端成对打开时才会开始执行
if(fd < ){
perror("open");
return -;
}
puts("fifo open success."); for(int i=;i<;i++){
puts("我是第一个进程");
}
sleep();
process_int = ; write(fd,&process_int,);
while();
return ;
}
second.c 进程2
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h> int main(int argc, char const *argv[])
{
int fd;
int process_int = ; fd = open("./fifo",O_RDONLY); //注,有名管道两端成对打开时才会开始执行
if(fd < ){
perror("open");
return -;
}
puts("fifo open success."); read(fd,&process_int,);
while(process_int == ); for(int i=;i<;i++){
puts("我是第二个进程");
} while();
return ;
}