一、无名管道
1、介绍
- 无名管道的通讯原理是在内核中完成的,无名管道只能在亲缘进程间通信。
- 无名管道的大小为64K,它是一个半双工的通信方式,无名管道在使用的时候不能使用 lseek 函数(因为原理和队列相似,先进先出)。
![1](https://i-blog.csdnimg.cn/blog_migrate/530c8500253464570ea0257bf3583906.webp?x-image-process=image/format,png#pic_center)
2、函数API
#include <unistd.h>
函数原型:
int pipe(int pipefd[2]);
参数:
@pipefd[2] : 是一个数组
pipefd[0] : 代表读端
pipefd[1] : 代表写端
返回值:
成功返回0 失败返回-1;
3、示例
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
int main(){
pid_t pid;
char buf[128] = {0};
int pipefd[2];
if ( pipe(pipefd) == -1){
printf("pipe error\n");return -1;
}
pid = fork();
if(pid == -1){
printf("fork error\n");return -1;
}else if(pid == 0){
close(pipefd[0]);
while(1){
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = '\0';
write(pipefd[1], buf, strlen(buf));
if(strcmp(buf, "quit") == 0)
break;
}
exit(0);
}else{
close(pipefd[1]);
while(1){
memset(buf, 0, sizeof(buf));
read(pipefd[0], buf, sizeof(buf));
if(strcmp(buf, "quit") == 0)
break;
printf("buf = %s\n", buf);
}
wait(NULL);
}
return 0;
}
4、无名管道读写规则
- 读端存在,对管道写,有多少写多少,直到写满为止(64K),再写会阻塞。
如果读写端都存在,如果只写不读,当管道写满是,写操作也会阻塞,默认无名管道64K字节。 - 写端存在,读(v.动词)管道,有多少读多少,如果管道数据为空,读阻塞。
如果读写端都存在,如果只读不写,如果管道有数据则正常读取,如果没有数据会一直阻塞。 - 读端不存在,写(v.动词)管道,管道破裂,进程会收到一个信号SIGPIPE
如果关闭读端,只有写端,当执行到write函数时,就会产生SIGPIPE(管道破裂)信号,信号默认的处理方式是退出整个进程。 - 写端不存在,读(v.动词)管道,有多少读多少,如果管道数据为空,立即返回。
如果关闭写端,只有读端,如果管道有数据则正常读取,如果没有数据则read会返回0
二、有名管道
1、介绍
- 可以在任意进程间通信,有名管道会在用户空间创建一个管道文件,管道文件是在内存存放的。
- 如果想要通过有名管道实现进程间通信,就在当前进程中打开一个管道文件,产生一个文件描述符 fd 并对其操作即可。
2、函数API
#include <sys/types.h>
#include <sys/stat.h>
函数原型:
int mkfifo(const char *pathname, mode_t mode)
参数:
@ pathname : 创建的管道的路径以及管道名称
@ mode : 管道的权限
返回值:
成功返回0 失败返回-1
3、示例
3.1、creat.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
int main(){
if( mkfifo("/fifo", 0666) == -1){
printf("mkfifo error");return -1;
}
getchar();
system("sudo rm fifo");
return 0;
}
3.2、write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main(){
int fd;
char buf[128] = {0};
if ((fd = open("/fifo", O_WRONLY)) == -1){
printf("open error\n");return -1;
}
while(1){
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = '\0';
write(fd, buf, strlen(buf));
if(strcmp(buf, "quit") == 0)
break;
}
close(fd);
return 0;
}
3.3、read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main(){
int fd;
char buf[128] = {0};
if ((fd = open("/fifo", O_RDONLY)) == -1){
printf("open error\n");return -1;
}
while(1){
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf));
if(strcmp(buf, "quit") == 0)
break;
printf("buf = %s\n", buf);
}
close(fd);
return 0;
}
4、有名管道读写规则
- 读端存在,写管道,有多少写多少,直到写满阻塞。
- 写端存在,读管道,有多少读多少,如果管道数据为空,读阻塞。
- 如果读端不存在,写管道: 读端没有打开过:写端在open的位置阻塞 读端打开又关闭了:写管道,管道破裂
- 如果写端不存在,读管道: 写端没有打开过:读端在open位置阻塞 写端打开有关闭了:管道中有多少数据就读多少,如果数据为空,立即返回。