无名管道pipe:
无名管道有读端和写端,并且读端只能读,写端只能写
#include <unistd.h>
函数原型:
int pipe(int pipefd[2]);
参数:
pipefd[0]: 读
pipefd[1]: 写
返回值:
成功:0
失败:-1
无名管道的特点:
a.没有名字,无法使用open()打开,只有文件描述符数组,不能使用lseek文件定位
b.只能用于亲缘进程之间(父子,兄弟,祖孙)通信(由父进程创建)
c.半双工工作方式,读写端是分开的,pipefd[0]为读端,pipefd[1]为写端,同一时刻,只能由一端写,另一端读
d.是一种特殊的文件,只存在于内存中,由内核进行管理,随进程生,随进程死
e.对于它的读写可以使用文件IO如read,write函数
f.没有办法保证写入数据的原子性(如果管道破裂,则数据丢失),管道缓冲区一有空闲区域,写进程就会试图向管道写入数据,如果读进程不读走管道缓冲区的数据,那么写操作将一直阻塞,
原子性:每一段数据都是独立的,不会被拆分,管道先进先出、顺序是有保证的,管道中的数据长度不是由实际的字符串长度决定,而是由写入的参数决定
g.无名管道的操作属于一次性操作,如果对无名管道进行读写操作,数据会被全部读走
单工:固定一种方向进行通信,广播(只能由A设备向B设备发送消息,不能由B向A发送)
半双工:方向不定,但是同一时间只能由一端发送到另一端,对讲机,(同一时间,只能由A设备向B设备发送消息,或者由B设备向A设备发送消息,否则就是自问自答)
全双工:通信方向都可以,同时可以发送也可以接收,电话
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
// 定义无名管道的文件描述符
int fd1[2];
char rbuf[50], wbuf[50];
// 创建无名管道
int ret1 = pipe(fd1);
//创建失败
if(ret1==-1)
{
perror("pipe error\n");
return -1;
}
// 创建子进程进行通信
pid_t son = fork();
if(son == 0) // 子进程
{
while(1)
{
//清空读端 写端
bzero(wbuf, sizeof(wbuf));
bzero(rbuf, sizeof(rbuf));
// 事情1:子进程给父进程发送数据
printf("请输入给父进程发送的数据:\n");
scanf("%s", wbuf);
//将数据写入无名管道
write(fd1[1], wbuf, sizeof(wbuf));
// 退出
if(!strcmp(wbuf, "quit"))
break;
// 事情2:
read(fd1[0], rbuf, sizeof(rbuf));
printf("子进程接收到的数据:%s\n", rbuf);
// 退出
if(!strcmp(rbuf, "quit"))
break;
}
// 退出子进程
exit(0);
}
else if(son > 0) // 父进程
{
while(1)
{
bzero(wbuf, sizeof(wbuf));
bzero(rbuf, sizeof(rbuf));
// 事情1:父进程接收子进程发送的数据
read(fd1[0], rbuf, sizeof(rbuf));
printf("父进程接收到的数据:%s\n", rbuf);
// 退出
if(!strcmp(rbuf, "quit"))
break;
// 事情2:
printf("请输入要给子进程发送的数据:\n");
scanf("%s", wbuf);
write(fd1[1], wbuf, sizeof(wbuf));
// 退出
if(!strcmp(wbuf, "quit"))
break;
}
}
// 等待子进程
wait(NULL);
// 关闭文件描述符
close(fd1[0]);
close(fd1[1]);
return 0;
}