【Linux】进程通信之命名管道mkfifo
1.认识命名管道
- 匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
- 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
- 命名管道是一种特殊类型的文件
2.在命令行上创建命名管道
基本语法:mkfifo fifoname
创建完命名管道后,进行简单的通信,如下图:
3.匿名管道与命名管道的区别
- 匿名管道由pipe函数创建并打开。
- 命名管道由mkfifo函数创建,打开用open
- FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。
4.命名管道的打开规则
4.1如果当前打开操作是为读而打开FIFO时
- O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
- O_NONBLOCK enable:立刻返回成功
4.2如果当前打开操作是为写而打开FIFO时
3. O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
4. O_NONBLOCK enable:立刻返回失败,错误码为ENXIO
5.用命名管道实现server&client通信
- 先定义公共的同文件,代码块如下:
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define MY_FIFO "./fifo"
- 编写server模块,代码如下:
#include "comm.h"
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
//该命令用来设置限制新文件权限的掩码。
umask(0);
//创建命名管道
if(mkfifo(MY_FIFO, 0666) < 0){
perror("mkfifo");
return 1;
}
//命名管道本质就是文件的一种,只需要文件操作即可
int fd = open(MY_FIFO, O_RDONLY);
if(fd < 0){
perror("open");
return 2;
}
//业务逻辑,可以进行对应的读写了
while(1){
char buffer[64] = {0};
sleep(50);
ssize_t s = read(fd, buffer, sizeof(buffer)-1); //键盘输入的时候,\n也是输入字符的一部分
if(s > 0){
//success
buffer[s] = 0;
if(strcmp(buffer, "show") == 0){
if(fork() == 0){
execl("/usr/bin/ls", "ls", "-l", NULL);
exit(1);
}
waitpid(-1, NULL, 0);
}
else if(strcmp(buffer, "run") == 0){
if(fork() == 0){
execl("/usr/bin/sl", "sl", NULL);
}
waitpid(-1, NULL, 0);
}
else{
printf("client# %s\n", buffer);
}
}
else if(s == 0){
//peer close
printf("client quit ...\n");
break;
}
else{
//error
perror("read");
break;
}
}
close(fd);
return 0;
}
- 编写client模块,代码如下:
#include "comm.h"
#include <string.h>
int main()
{
//用不用在创建fifo?? 我只要获取即可
int fd = open(MY_FIFO, O_WRONLY); //不需要O_CREAT
if(fd < 0){
perror("open");
return 1;
}
//业务逻辑
while(1){
printf("请输入# ");
fflush(stdout);
char buffer[64] = {0};
//先把数据从标准输入拿到我们的client进程内部
ssize_t s = read(0, buffer, sizeof(buffer)-1);
if(s > 0){
buffer[s-1] = 0;
printf("%s\n", buffer);
//拿到了数据
write(fd, buffer, strlen(buffer)); //要不要-1,不需要
}
}
close(fd);
return 0;
}