Linux进程间通信-管道深入理解
Linux进程通信系列文章将详细介绍各种通信方式的机制和区别
1.进程间通信
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。
2、进程间通信方式
3、进程间通信-管道(pipe)
3.1 管道是如何通信的
(1)父进程创建管道,得到两个⽂件描述符指向管道的两端
(2)父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。
(3)父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。
3.2 利用管道实现通信
#include "stdio.h"
#include "unistd.h"
#include "string.h"
int main(int argc, char* argv[])
{
int fd[2];
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe error\n");
return 1;
}
pid_t pid = fork();
if (pid == 0) // child
{
close(fd[0]);
int i = 0;
char* msg = "i am child\n";
while (i < 5)
{
write(fd[1],msg,strlen(msg));
sleep(2);
i++;
}
}
else if(pid > 0)
{
close(fd[1]);
char buf[256] = {0};
int j = 0;
while (j < 5)
{
int n = read(fd[0],buf,256);
if (n>0)
{
buf[n] = '\0';
}
printf("%s",buf);
j++;
}
}
else
{
perror("fork error\n");
return 1;
}
return 0;
}
运行结果:
3.3 管道读取数据的四种的情况
(1)读端不读,写端一直写
(2)写端不写,读端一直读
(3)读端一直读,写端关闭
(4)写端一直写,读端关闭
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "sys/wait.h"
#include "sys/types.h"
int main(int argc, char* argv[])
{
int fd[2];
int status = 0;
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe error\n");
return 1;
}
pid_t pid = fork();
if (pid == 0) // child
{
close(fd[0]);
int i = 0;
char* msg = "i am child\n";
while (i < 10)
{
write(fd[1],msg,strlen(msg));
sleep(1);
i++;
}
}
else if(pid > 0)
{
close(fd[1]);
char buf[256] = {0};
int j = 0;
while (j < 5)
{
int n = read(fd[0],buf,256);
if (n>0)
{
buf[n] = '\0';
}
printf("%s",buf);
j++;
}
close(fd[0]);
ret = waitpid(pid,&status,0);
printf("exit single(%d),exit(%d)\n", status & 0xff, (status >> 8) & 0xff);
}
else
{
perror("fork error\n");
return 1;
}
return 0;
}
运行结果:
使用kill -l 查看13号信号,可以知道13号信号代表SIGPIPE。
4、管道的特点
(1)管道只允许具有血缘关系的进程间通信,如父子进程间的通信。
(2)管道只允许单向通信。
(3)管道内部保证同步机制,从而保证访问数据的一致性。
5、管道的容量
测试管道容量大小只需要将写端一直写,读端不读且不关闭fd[0],即可。
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "sys/wait.h"
#include "sys/types.h"
int main(int argc, char* argv[])
{
int fd[2];
int status = 0;
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe error\n");
return 1;
}
pid_t pid = fork();
if (pid == 0) // child
{
close(fd[0]);
int i = 1;
while (i)
{
write(fd[1],"A",1);
printf("pipe capacity: %d\n",i++);
}
close(fd[1]);
}
else if(pid > 0)
{
close(fd[1]);
waitpid(pid,NULL,0);
close(fd[0]);
}
else
{
perror("fork error\n");
return 1;
}
return 0;
}
运行结果:
由此可见,管道大小为64k