进程间通信
进程进通信简介
假如A进程和B进程想要通信,按照之间讲解的进程的原理是无法完成的,A和B进程的内存空间是独立的0-3G。如果想要实现通信就必须借助内核空间才能完成,因为内核空间是共用的。在linux系统中进程间通信的方式有7种。
(1)传统进程间通信(3种)
1.无名管道
2.有名管道
3.信号
(2)system V版本引入IPC进程间通信(3种)
1.消息队列
2.共享内存
3.信号灯集
(3)BSD(伯克利分校)版本中引入的socket通信
1.套接字通信(通过网络实现进程间通信)
(4)Android系统中
1.binder机制
无名管道
无名管道通信的原理
无名管道只能由于亲缘关系的进程间通信,无名管道是在内核中实现的。如果A和B进程想要通过无名管道通信,A向管道的一端发送消息,B进程从管道的另外一端读取消息即可。无名管道的通信方式不支持使用lseek函数。无名管道的大小是64K。如果A一直往管道中写数据,B不读取。A写满的时候就会阻塞。如果A没有写,B取读取数据,B进程阻塞。无名管道是半双工的通信方式。
A和B的通信方式:
单工: A------------->B
半双工:在同一时刻内只能一边发一边收
A------>B A<-------B
全双工:在同一时刻两边都可以收发
A<-------->B
无名管道的API
int pipe(int pipefd[2]);
功能:Pipe()创建一个管道,这是一个可以用于进程间通信的单向数据通道。
数组pipefd用于返回引用管道两端的两个文件描述符。Pipefd [0]是指
管道的读端。Pipefd[1]指管道的写端。写入到管道写端的数据由内核进
行缓冲,直到从管道读端读取。
参数:
@pipefd :返回管道两端的文件描述符
pipefd[0]读端
pipefd[1]写端
返回值:成功返回0,失败返回-1置位错误码
无名管道的实例
#include <head.h>
int main(int argc, const char* argv[])
{
pid_t pid;
int pipefd[2];
char buf[128] = {
0 };
// 1.创建无名管道
if (pipe(pipefd))
PRINT_ERR("pipe error");
// 2.创建进程
pid = fork();
if (pid == -1) {
PRINT_ERR("fork error");
} else if (pid == 0) {
close(pipefd[0]); // 关闭子进程的读端
// 子进程向管道中写数据 pipefd[1]
while (1) {
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = '\0';
write(pipefd[1], buf, strlen(buf));
if (strcmp(buf, "quit") == 0)
break;
}
close(pipefd[1]);
exit(0);
} else {
close(pipefd[1]); // 关闭父进程的写端
// 从管道中读数据 pipefd[0]
while (1) {
memset(buf, 0, sizeof(buf));
read(pipefd[0], buf, sizeof(buf));
if (strcmp(buf, "quit") == 0)
break;
printf("buf = %s\n", buf);
}
close(pipefd[0]);
wait(NULL);
}
return 0;
}
无名管道的特点
1.只能用于亲缘关系的进程的通信
2.无名管道是半双工的通信方式
3.不支持使用lseek函数
4.无名管道的大小是64K
#include <head.h>
int main(int argc, const char* argv[])
{
pid_t pid;
int pipefd[2];
char buf[128] = {
0 };
// 1.创建无名管道
if (pipe(pipefd))
PRINT_ERR("pipe error");
for(int i=0;i<65537;i++){
write(pipefd[1],"a",1); //写第65537个字符的时候,因为管道满了,写阻塞
printf("i = %d\n",i);
}
printf("********************\n"); //这句话不打印
return 0;
}
无名管道读写的特点
读端存在,写管道 :有多少写多少,直到写满(64K)位置。
#include <head.h>
int main(int argc, const char* argv[])
{
pid_t pid;