Linux进程间通信—管道
前言:本篇主要总结介绍了Linux进程间通信方式之一管道技术。包括管道(无名有名)的基本概念、相关API的介绍、及Demo代码示例。
关于管道
管道是UNIX系统最古老的一种 IPC 方式,所有UNIX系统都提供这种通信机制。
管道 | 接口 | 特性 |
---|---|---|
无名管道 | pipe | 半双工为主、父子进程间通信 |
命名管道 FIFO | mkfifo 和 mkfifoat | 多个不相关进程间通信 |
- int pipe(int pipefd[2])
该函数经由参数 pipefd 返回两个文件描述符:pipefd[0] 为读打开,pipefd[1] 为写打开。pipefd[1] 的输出是 pipefd[0] 的输入 - int mkfifo(const char *pathname, mode_t mode)
- int mkfifoat(int dirfd, const char *pathname, mode_t mode)
使用 mkfifo 和 mkfifoat 两个接口来创建 FIFO 文件,其中参数 mode 与 open 函数中的 mode 相同;
mkfifoat 与 mkfifo 相似,其中 fd 用来在 fd 文件描述符表示的目录相关的位置创建一个 FIFO。
父子进程间的管道通信
一般,进程先调用 pipe,再调 fork,从而创建从父进程到子进程的 IPC 管道,如图所示:
下面来创建一个父子进程间的通信管道,子进程通过该管道像父进程传送数据,父进程使用该数据。Demo 程序如下:
#define BUFSIZE 512
static void PipeDemo()
{
int fd[2];
pid_t pid;
char buf[BUFSIZE] = {0};
int readsize = 0;
if(pipe(fd) < 0) {
printf("pipe failed!\n");
return;
}
if((pid = fork()) < 0) {
printf("fork failed!\n");
return;
}
else if(pid == 0) {
close(fd[0]);
printf("Child Process Say Hello to Father Process\n");
write(fd[1], "Hello Father\n", 13);
}
else {
close(fd[1]);
readsize = read(fd[0], buf, BUFSIZE);
if(strcmp(buf, "Hello Father\n") == 0) {
printf("OK, Good Boy\n");
}
}
exit(0);
}
该程序测试执行后打印如下:
函数 popen 和 pclose
- FILE *popen(const char *command, const char *type)
函数 popen 先执行 fork,然后调用 exec 执行 command,并且返回一个标准 I/O 文件指针。
如果 type 是 “r”,则文件指针链接到 command 的标准输出;
如果 type 是 “w”,则文件指针链接到 command 的标准输入; - int pclose(FILE *stream)
on success, returns the exit status of the command; if wait4(2) returns an error, or some other error is detected, -1 is returned.
下面使用 popen 执行一个 ls 命令,并打印结果:
static void PopenDemo()
{
FILE *fd = NULL;
char buf[BUFSIZE] = {0};
size_t n = 0;
fd = popen("ls -l", "r");
n = fread(buf, BUFSIZE, 1, fd);
printf("%s", buf);
if(pclose(fd) == -1) {
printf("pclose failed.");
}
}
执行结果如下:
FIFO 命名管道
FIFO 是一种文件类型,通过FIFO,不相干的进程之间也能交换数据。
下面就使用 mkfifo 函数来创建一个 FIFO 文件,并用与不同进程间通信。
该Demo程序通过 fifo 接收其他进程的消息,并作出回应
// fifo.c create 2020/5/26
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
static void ModifyFIFO()
{
const char *fifofile = "/tmp/fifo";
if(access(fifofile, F_OK) != 0) {
if(mkfifo(fifofile, 0755) != 0) {
printf("mkfifo failed.");
exit(0);
}
}
int fd = open(fifofile, O_RDWR);
if(fd < 0) {
printf("open fifo failed.");
exit(0);
}
char buf[512] = {0};
int size = 0;
while(1) {
memset(buf, 0, 512);
size = read(fd, buf, 512);
if(size > 0) {
printf("%s\n", buf);
}
if(strstr(buf, "exit")) {
break;
}
else if(strstr(buf, "Hello Dad")) {
write(fd, "OK, Good boy~", 13);
}
}
}
int main()
{
ModifyFIFO();
return 0;
}
不同进程之间执行效果如下:
所有博客均在CSDN首发 Caso_卡索 https://blog.csdn.net/xiaoma_2018