图控大叔
构图传递思想
阅读从未如此简单!!!
01
前言
今天来说说Linux进程间通信:匿名管道。Linux环境下,进程间的通信方式有很多,有管道,IPC机制下的消息队列、共享内存和信号量,Posix机制下的有名信号量和无名信号量。今天要分享的内容是亲缘进程间的通信方式:匿名管道。待分享的内容还很多,慢慢来!
02
细述
匿名管道的特点匿名管道,又称无名管道
特点:
1,它只能作用于亲缘进程
1.1、匿名管道的创建使用pipe创建,诞生出两个操作管道读写端的文件描述符
1.2、只有创建子进程的时候才会被继承过去,无法通过别的方式打开同一个管道
2,半双工通信(在读的时候不能写入,在写入的时候不能读取)
3,操作无原子性
4,无法用lseek定位操作位置
5,匿名管道比命名管道需要更少的开销,但是提供有限的服务。
管道的特点在于他本身拥有读写阻塞特性,
你可以利用这一个特性制造出属于自己的特殊的缓冲区(数据的同步互斥特性)
相关API
匿名管道需包含头文件
#include
匿名管道相关API
1、创建匿名管道
int pipe(int pipefd[2]);
2、读操作
read(pipefd[0], file, sizeof(file)));
3、写操作
write(pipefd[1], file, sizeof(file)));
4、关闭:关闭文件描述符
close(pipefd[0]);
close(pipefd[1]);
部分函数说明
匿名管道创建函数
int pipe(int pipefd[2]);
函数功能:
随机创建一个匿名管道,并且返回管道的两个通信文件描述符给传入的数组
pipefd:这是一个(两个int型元素的数组),
管道创建成功后会将读端文件描述符放到第0个元素中,
读端:pipefd[0]
将写端文件描述符放到第1个元素中
写端:pipefd[1]
返回值:
成功返回0,失败返回-1
其他说明
其他说明
1、匿名管道的使用只能在亲缘进程间
2、匿名管道在父、子进程继承的时候,管道依旧是一个管道,
但是每个进程都拥有自己的文件描述符,
即读端:pipefd[0]
写端:pipefd[1]
因此,父进程的读端关闭,仅影响父进程的读端操作,
不影响子进程的读端操作。反之亦然
参考代码
#include
#include
#include
#include
int main(void){
int pipe_fd[2];
int retval;
pid_t cpid;
char buffer[1024];
retval = pipe(pipe_fd);
if(retval == -1)
{
perror("create pipe error");
return -1;
}
cpid = fork();
if(cpid == 0)
{
ssize_t rd_ret;
int C_write_num = 0;
int C_read_num = 0;
while(1)
{
bzero(buffer, sizeof(buffer));
rd_ret = write(pipe_fd[1], "子进程写进去的", strlen("子进程写进去的"));
if(rd_ret == -1)
{
perror("子进程写失败\n\n");
//exit(EXIT_FAILURE);为了观察实验现象而注释
}
if(C_write_num == 6)
{
close(pipe_fd[1]);
printf("子进程 写端关闭\n\n");
rd_ret = read(pipe_fd[0], buffer, sizeof(buffer));
if(rd_ret == -1)
{
perror("子进程 读端失败\n");
exit(EXIT_FAILURE);
}
C_read_num++;
printf("子进程 第 %d 读结束 %s\n\n", C_read_num,buffer);
sleep(1);
}
else
{
C_write_num++;
printf("子进程 第 %d 写结束 \n\n", C_write_num);
sleep(1);
}
}
exit(EXIT_SUCCESS);
}
ssize_t rd_ret_2;
int F_write_num = 0;
int F_read_num = 0;
while(1)
{
bzero(buffer, sizeof(buffer));
rd_ret_2 = read(pipe_fd[0], buffer, sizeof(buffer));
if(rd_ret_2 == -1)
{
perror("父进程读失败\n\n");
//exit(EXIT_FAILURE);为了观察实验现象而注释
}
if(F_read_num == 6)
{
F_write_num++;
close(pipe_fd[0]);
rd_ret_2 = write(pipe_fd[1], "父进程写入的", strlen("父进程写入的"));
if(rd_ret_2 == -1)
{
perror("父进程写失败\n");
exit(EXIT_FAILURE);
}
printf("父进程开始第 %d 次写入的\n\n",F_write_num);
sleep(1);
}
else
{
F_read_num++;
printf("父进程是第 %d 次读取的是 %s\n\n", F_read_num,buffer);
sleep(1);
}
}
close(pipe_fd[0]);
close(pipe_fd[1]);
return 0;
}
参考代码说明
首先
并且往pipe_fd数组当中的0元素填充管道的读端文件描述符,
往1元素填充管道写端文件描述符
其次
通过fork函数创建子进程
再者
通过在子进程及父进程中设置读、写6次后,
进行相应的读、写端文件描述符关闭,并且进行打印测试
最后
观察实验现象
说明,在此处有注释的情况,是为了更好的观察现象,如
//exit(EXIT_FAILURE);
而在正常情况下不能关闭
03
结尾
今天的分享就到这里,系统编程系列的内容还有很多内容需要分享,再接再厉!