• 正文
  • 相关推荐
申请入驻 产业图谱

飞凌嵌入式ElfBoard-进程间的通信之命名管道

2小时前
110
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

命名管道(FIFO)与匿名管道(PIPE)的不同的地方在于,命名管道在文件系统中具有一个名字,可以使得不相关的进程也能通过该名字访问管道。

Linux中可以使用mkfifo命令和mknod命令创建命名管道;mkfifo专用于创建命名管道(FIFO)。mknod命令用于创建设备文件,字符设备,块设备或FIFO。

mkfifo 命令非常简单,用法如下:

mkfifo <fifo_name>

mknod 命令稍微复杂一些,因为它需要指定设备类型。创建命名管道的命令如下:

mknod <fifo_name> p

例如创建一个命名管道my_fifo

mkfifo my_fifo

可以通过echo和cat命令操作FIFO进行读写,在两个终端中分别执行下面两条命令,执行cat的终端就会收到test!的信息;执行cat my_fifo后命名管道是阻塞的,直到有进程将数据写入my_fifo。

cat my_fifo

echo "test!" > my_fifo

应用程序中也可以使用mkfifo命令的同名函数mkfifo()来创建FIFO;mknod()是比较老的函数,而使用mkfifo()函数更加简单和规范,所以建议在可能的情况下,尽量使用mkfifo()而不是mknod()。

mkfifo专用于创建命名管道(FIFO)。

1.头文件

#include <sys/types.h>

#include <sys/stat.h>

2.函数原型

int mkfifo(const char *pathname, mode_t mode);

3.参数

pathname:表示要创建的命名管道的路径和名称。是一个字符指针,指定命名管道的路径,可以是相对路径或绝对路径。例如,/tmp/my_fifo 或 my_fifo(在当前目录下)。

mode:指定文件的权限模式。是一个 mode_t 类型的值,用于指定 FIFO 的访问权限,与 open() 或 chmod() 使用的权限模式类似。

权限值一般包括:

S_IRUSR (0400):用户可读

S_IWUSR (0200):用户可写

S_IRGRP (0040):组可读

S_IWGRP (0020):组可写

S_IROTH (0004):其他用户可读

S_IWOTH (0002):其他用户可写

例如,0666 表示用户、组和其他用户都可读写。

4.返回值

函数成功返回 0,否则返回-1 并设置 errno,与其他文件一样,FIFO文件也可以使用open、read、write、close调用来进行读写。

5.示例:通过mkfifo()函数创建命名管道通信

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <fcntl.h>

#include <string.h>

#include <errno.h>

int main() {

const char *fifo_path = "/tmp/my_fifo";

char buffer[256];

pid_t pid;

// 创建命名管道

if (mkfifo(fifo_path, 0666) == -1) {

if (errno != EEXIST) {

perror("mkfifo");

exit(EXIT_FAILURE);

}

}

// 创建子进程

pid = fork();

if (pid == -1) {

perror("fork");

exit(EXIT_FAILURE);

}

if (pid == 0) {

// 子进程:写入数据

int fifo_fd = open(fifo_path, O_WRONLY);

if (fifo_fd == -1) {

perror("open for write");

exit(EXIT_FAILURE);

}

const char *message = "Hello from child process!";

write(fifo_fd, message, strlen(message) + 1); // +1 to include '\0'

close(fifo_fd);

printf("Child process: Wrote message to FIFO\n");

} else {

// 父进程:读取数据

int fifo_fd = open(fifo_path, O_RDONLY);

if (fifo_fd == -1) {

perror("open for read");

exit(EXIT_FAILURE);

}

read(fifo_fd, buffer, sizeof(buffer));

printf("Parent process: Read message from FIFO: %s\n", buffer);

close(fifo_fd);

// 删除管道文件

unlink(fifo_path);

}

return 0;

}

6.运行结果

Parent process: Read message from FIFO: Hello from child process!

Child process: Wrote message to FIFO

7.程序解析

使用 mkfifo() 创建命名管道。父进程和子进程通过 fork() 创建,并通过 open()、write()、read() 函数进行通信。父进程在读取完数据后,删除命名管道文件。

将这个程序中的父子进程拆成两个程序,编译之后打开两个终端执行;writer 程序通过 mkfifo() 确保管道存在,然后打开管道写入数据。reader 程序打开管道读取数据,并在读取完数据后删除管道文件。

8.写入数据的程序(writer.c)

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <fcntl.h>

#include <string.h>

#include <errno.h>

int main() {

const char *fifo_path = "/tmp/my_fifo";

// 创建命名管道

if (mkfifo(fifo_path, 0666) == -1) {

if (errno != EEXIST) {

perror("mkfifo");

exit(EXIT_FAILURE);

}

}

// 打开管道进行写入

int fifo_fd = open(fifo_path, O_WRONLY);

if (fifo_fd == -1) {

perror("open for write");

exit(EXIT_FAILURE);

}

const char *message = "Hello from writer program!";

write(fifo_fd, message, strlen(message) + 1); // +1 to include '\0'

printf("Writer: Message written to FIFO\n");

close(fifo_fd);

return 0;

}

9.读取数据的程序(reader.c)

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <fcntl.h>

#include <string.h>

#include <errno.h>

int main() {

const char *fifo_path = "/tmp/my_fifo";

char buffer[256];

// 打开管道进行读取

int fifo_fd = open(fifo_path, O_RDONLY);

if (fifo_fd == -1) {

perror("open for read");

exit(EXIT_FAILURE);

}

read(fifo_fd, buffer, sizeof(buffer));

printf("Reader: Message read from FIFO: %s\n", buffer);

close(fifo_fd);

// 删除管道文件

unlink(fifo_path);

return 0;

}

相关推荐