linux进程间通信:匿名管道&&命名管道
Posted mbf330
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux进程间通信:匿名管道&&命名管道相关的知识,希望对你有一定的参考价值。
linux进程间通信:匿名管道&&命名管道
什么是管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
1.匿名管道
#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数:fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码
(1)匿名管道的代码实现以及分析:
管道的四个重要结论
1.当实际读取时,如果读取条件不满足,读取端会阻塞。(管道为空)
2.当实际写入时,如果写入条件不满足,写入端会阻塞。(管道已写满)
3.如果写端不写且关闭文件描述符,读端会读到文件结尾。
4.如果读端关闭,写端进程可能会被系统直接杀掉。
在这段代码中,写端(子进程)每隔一秒写入一次,读端(父进程)便读取一次,实现一个简单的匿名管道,并以此来分析上述四个结论。
a.当实际读取时,如果读取条件不满足,读取端会阻塞。(管道为空)
写端每隔一秒写入一次,读端不断读取,读取条件不满足时,读取端会阻塞。在运行截图中,每读取一次便会空一行,便是读端阻塞的结果
#include<stdio.h>
#include<unistd.h>
#include<string.h>
//当实际读取时,如果读取条件不满足,读取端会阻塞(管道为空)
//当实际写入时,如果写入条件不满足,写入端会阻塞(管道已写满)
//如果写端不写且占用文件描述符,读端不会阻塞
//如果读端关闭,写端进程可能会被系统直接杀掉
int main()
//文件描述符数组,pipefd[0]为读,pipefd[1]为写
int pipefd[2]=0;
pipe(pipefd);
//创建进程
pid_t id=fork();
if(id==0)
//child,write
//防止读写同时进行,关闭读区
close(pipefd[0]);
const char *msg="I am child!\\n";
int count=0;
while(1)
//write函数,返回值为:数组下标,字符串,字符串长度
write(pipefd[1],msg,strlen(msg));
//写端每隔一秒写入一次
sleep(1);
printf("child:%d\\n",count++);
else
//father,read
close(pipefd[1]);
char buffer[64];
while(1)
//关闭写区
close(pipefd[1]);
//read函数,返回值:数组下标(从哪读),字符数组(读到哪),常量(读多少)
ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
if(s>0)
//以‘0’结尾
buffer[s]=0;
//父进程读取子进程所写的消息
printf("father get message:%s\\n",buffer);
//sleep(1);
return 0;
b.当实际写入时,如果写入条件不满足,写入端会阻塞。(管道已写满)
在这段代码中,写端不断写入,读端每隔一秒读取一次,写入条件不满足时,写端阻塞。
if(id==0)
//child,write
//防止读写同时进行,关闭读区
close(pipefd[0]);
const char *msg="I am child!\\n";
int count=0;
while(1)
//write函数,返回值为:数组下标,字符串,字符串长度
write(pipefd[1],msg,strlen(msg));
//写端每隔一秒写入一次
//sleep(1);
printf("child:%d\\n",count++);
else
//father,read
close(pipefd[1]);
char buffer[64];
while(1)
//关闭写区
close(pipefd[1]);
//read函数,返回值:数组下标(从哪读),字符数组(读到哪),常量(读多少)
ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
if(s>0)
//以‘0’结尾
buffer[s]=0;
//父进程读取子进程所写的消息
printf("father get message:%s\\n",buffer);
//每隔一秒读取一次
sleep(1);
在上述两个实例中,子进程与父进程一个慢时另一个也慢,一个快时另一个也快,叫做进程间同步。
c.如果写端不写且关闭文件描述符,读端会读到文件结尾。
在这段代码中,写端写入五次后,关闭写端,读端仍然不断读取,最终读到文件结尾。
if(id==0)
//child,write
//防止读写同时进行,关闭读区
close(pipefd[0]);
const char *msg="I am child!\\n";
int count=0;
while(1)
//write函数,返回值为:数组下标,字符串,字符串长度
write(pipefd[1],msg,strlen(msg));
//写端每隔一秒写入一次
//sleep(1);
printf("child:%d\\n",count++);
if(count==5)
//count为5时,关闭写端
close(pipefd[1]);
break;
exit(2);
else
//father,read
close(pipefd[1]);
char buffer[64];
while(1)
//关闭写区
close(pipefd[1]);
//read函数,返回值:数组下标(从哪读),字符数组(读到哪),常量(读多少)
ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
if(s>0)
//以‘0’结尾
buffer[s]=0;
//父进程读取子进程所写的消息
printf("father get message:%s\\n",buffer);
//每隔一秒读取一次
sleep(1);
printf("father exit return :%d",s);
d.如果读端关闭,写端进程可能会被系统直接杀掉。
这段代码中,读端读取三秒后关闭,写端(子进程)变成僵尸进程,被系统杀掉
if(id==0)
//child,write
//防止读写同时进行,关闭读区
close(pipefd[0]);
const char *msg="I am child!\\n";
int count=0;
while(1)
//write函数,返回值为:数组下标,字符串,字符串长度
write(pipefd[1],msg,strlen(msg));
//写端每隔一秒写入一次
//sleep(1);
printf("child:%d\\n",count++);
if(count==5)
//count为5时,关闭写端
close(pipefd[1]);
break;
exit(2);
else
//father,read
close(pipefd[1]);
char buffer[64];
while(1)
//关闭写区
close(pipefd[1]);
int count=0;
//read函数,返回值:数组下标(从哪读),字符数组(读到哪),常量(读多少)
ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
if(s>0)
//以‘0’结尾
buffer[s]=0;
//父进程读取子进程所写的消息
printf("father get message:%s\\n",buffer);
//每隔一秒读取一次
sleep(1);
if(count++==3)
close(pipefd[0]);
(2)管道的特点
1.只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
2.管道提供流式服务。
3.一般而言,进程退出,管道释放,所以管道的生命周期随进程。
4.一般而言,内核会对管道操作进行同步与互斥。
5.管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。
2.命名管道
1.匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
2.如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道
。
3.命名管道是一种特殊类型的文件
(1)匿名管道与命名管道的关系
1.匿名管道由pipe函数创建并打开。
2.命名管道由mkfifo函数创建,打开用open。
3.FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。
(2)简单命名管道的创建
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
int main()
//创建一个命名管道,名为fifoTest,如果失败打印mkfifo faild!
if(-1==mkfifo("./fifoTest",2333))
perror("mkfifo faild!\\n");
return 1;
(3)命名管道中实现简单的通信
创建两个不相关的进程:server.c和client.c,在client中输入字符串,在server中读取。
//server.c
#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#define FIFO_FILE "./fifo"
int main()
umask(0);
if(-1==mkfifo(FIFO_FILE,0666))
perror("mkfifo faild!\\n");
return -1;
//打开命名管道“./fifo”
int fd=open("FIFO_FILE",O_RDONLY);
char buf[100];
if(fd>=0)
while(1)
//buf从client进程读取字符串
ssize_t s=read(fd,buf,sizeof(buf)-1);
//读取成功则打印字符串
if(s>0)
buf[s]=0;
printf("client#%s",buf);
else if(s==0)
printf("client quit,me too!\\n");
break;
//读取失败打印read faild!
else
perror("read faild!\\n");
break;
return 0;
//client.c
int main()
//打开命名管道
int fd=open(FIFO_FILE,O_WRONLY);
if(fd<0)
perror("open error!\\n");
return 1;
else
while(1)
printf("please enter message#");
fflush(stdout);
char buf[100];
ssize_t s = read(0,buf,sizeof(buf)-1);
if(s>0)
//'\\0'结尾
buf[s]=0;
write(fd,buf,s);
return 0;
运行结果:
以上是关于linux进程间通信:匿名管道&&命名管道的主要内容,如果未能解决你的问题,请参考以下文章