乐趣区

关于人工智能:Linux进程通信-管道与FIFO

Linux 过程间通信通常应用的形式有很多种,其中比拟罕用的包含管道(pipe)和 FIFO(命名管道)。本文将介绍这两种通信形式的基本概念,并用 C 语言编写示例代码,来阐明如何在两个过程之间应用这些 IPC 机制进行通信。

管道(pipe)

管道是一种半双工的通信形式,用于父过程和子过程之间的通信。在 Linux 中,管道是一种非凡的文件,有两个端点,一个读端和一个写端。管道的基本操作包含创立管道、敞开文件描述符、读取数据和写入数据等。

创立管道

在 Linux 中,咱们能够应用 pipe() 零碎调用来创立管道。pipe() 函数的原型如下:

#include <unistd.h>
int pipe(int pipefd[2]);

其中,pipefd 是一个数组,用于存储管道的读端和写端的文件描述符。pipe() 函数胜利时返回 0,失败时返回 -1。

上面是一个创立管道的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{int pipefd[2];
    
    // 创立管道
    if (pipe(pipefd) == -1) {perror("pipe");
        exit(EXIT_FAILURE);
    }
    
    printf("读端文件描述符:%d\n", pipefd[0]);
    printf("写端文件描述符:%d\n", pipefd[1]);
    
    exit(EXIT_SUCCESS);
}
  • 编译并运行,打印如下
 读端文件描述符:3
写端文件描述符:4

管道的读写

在应用管道进行通信时,父过程和子过程能够通过管道进行数据的读取和写入。在 C 语言中,咱们能够应用 read() 函数和 write() 函数来读取和写入数据。read() 函数用于从管道中读取数据,write() 函数用于向管道中写入数据,应用 close() 函数敞开文件描述符。在管道的应用中,咱们应该在不须要的时候敞开管道的读端和写端,以防止资源节约。

这三个函数的原型别离如下:

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);

上面是一个父过程向子过程写入数据并读取返回后果的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

#define BUF_SIZE 1024

int main()
{int pipefd[2];
    pid_t pid;
    char buf[BUF_SIZE];
    int status;
    
    // 创立管道
    if (pipe(pipefd) == -1) {perror("pipe");
        exit(EXIT_FAILURE);
    }
    
    // 创立子过程
    pid = fork();
    if (pid == -1) {perror("fork");
        exit(EXIT_FAILURE);
    }
    
    if (pid == 0) { // 子过程        
        // 从管道中读取数据
        if (read(pipefd[0], buf, BUF_SIZE) == -1) {perror("read");
            exit(EXIT_FAILURE);
        }
        
        printf("子过程收到音讯:%s\n", buf);
        
        // 发送音讯给父过程
        const char* message = "Hello, parent!";
        if (write(pipefd[1], message, strlen(message) + 1) == -1) {perror("write");
            exit(EXIT_FAILURE);
        }
        close(pipefd[1]); // 敞开写端
        exit(EXIT_SUCCESS);
    } else { // 父过程 
        // 发送音讯给子过程
        const char* message = "Hello, child!";
        if (write(pipefd[1], message, strlen(message) + 1) == -1) {perror("write");
            exit(EXIT_FAILURE);
        }
        
        // 期待子过程退出
        wait(&status);
        if (WIFEXITED(status)) {printf("子过程退出,返回值:%d\n", WEXITSTATUS(status));
        }
        
        // 从管道中读取数据
        if (read(pipefd[0], buf, BUF_SIZE) == -1) {perror("read");
            exit(EXIT_FAILURE);
        }
        printf("父过程收到音讯:%s\n", buf);
        close(pipefd[0]); // 敞开读端
        
        exit(EXIT_SUCCESS);
    }
}

在这个示例代码中,父过程先向子过程发送一条音讯,子过程收到音讯后向父过程发送一条音讯,并退出。父过程在期待子过程退出后再从管道中读取子过程发送的音讯。

  • 编译并运行,打印如下
 子过程收到音讯:Hello, child!
子过程退出,返回值:0
父过程收到音讯:Hello, parent!

FIFO(命名管道)

FIFO(命名管道)是一种文件系统对象,与管道相似,也能够用于过程间通信。FIFO 是一种非凡类型的文件,它能够在文件系统中被创立,并且过程能够通过文件描述符来读取和写入数据。

与管道不同的是,FIFO 能够被多个过程关上,并且能够在文件系统中以门路的模式存在,因而不像管道那样只能在具备亲缘关系的过程之间应用。任何过程只有有相应的权限就能够关上 FIFO 并进行通信。

FIFO 的创立和应用

FIFO 的创立和应用也比较简单。首先须要应用 mkfifo() 函数创立 FIFO 文件,其原型如下

#include <sys/types.h>
#include <sys/stat.h>

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

其中,pathname 是 FIFO 文件的路径名,mode 是文件的权限。

创立 FIFO 文件后,就能够像应用一般文件一样关上它,并应用 read() 和 write() 函数进行数据的读写。

上面是一个应用 FIFO 进行过程间通信的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO_PATH "/tmp/myfifo"
#define BUF_SIZE 1024

int main()
{
    int fd;
    char buf[BUF_SIZE];
    
    // 创立 FIFO 文件
    if (mkfifo(FIFO_PATH, 0666) == -1) {perror("mkfifo");
        exit(EXIT_FAILURE);
    }
    
    // 关上 FIFO 文件
    fd = open(FIFO_PATH, O_RDWR);
    if (fd == -1) {perror("open");
        exit(EXIT_FAILURE);
    }
    
    // 向 FIFO 中写入数据
    const char* message = "Hello, world!";
    if (write(fd, message, strlen(message) + 1) == -1) {perror("write");
        exit(EXIT_FAILURE);
    }
    
    // 从 FIFO 中读取数据
    if (read(fd, buf, BUF_SIZE) == -1) {perror("read");
        exit(EXIT_FAILURE);
    }
    
    printf("收到音讯:%s\n", buf);
    
    // 敞开文件描述符并删除 FIFO 文件
    close(fd);
    if (unlink(FIFO_PATH) == -1) {perror("unlink");
        exit(EXIT_FAILURE);
    }
    
    exit(EXIT_SUCCESS);
}

在这个示例代码中,程序先创立了一个 FIFO 文件 /tmp/myfifo,而后关上该文件并向其中写入一条音讯。接下来从 FIFO 文件中读取数据,并将其打印进去。最初敞开文件描述符并删除 FIFO 文件。

  • 编译并运行,打印如下
 收到音讯:Hello, world!

小结

Linux 中管道和 FIFO 是过程间通信的重要形式。管道只能用于亲缘关系的过程间通信,而 FIFO 能够被多个过程关上,不受过程之间关系的限度。无论是管道还是 FIFO,它们的应用形式都与一般文件相似,须要应用文件描述符和 read()、write() 函数来进行数据的读写。

在应用管道和 FIFO 进行过程间通信时,须要留神以下几点:

  1. 管道和 FIFO 只能用于同一主机上的过程间通信,不能用于跨主机通信。
  2. 管道和 FIFO 的读写操作是阻塞的,这意味着当一个过程尝试从一个空管道或 FIFO 中读取数据时,它会被阻塞,直到有数据可用为止。同样,当一个过程尝试将数据写入一个满的管道或 FIFO 时,它也会被阻塞,直到有闲暇空间为止。
  3. 在应用管道和 FIFO 进行过程间通信时,须要留神文件描述符的敞开程序。
  4. 管道和 FIFO 只能传输字节流,不能传输其余类型的数据,如构造体或指针。
  5. 如果应用管道或 FIFO 进行过程间通信时,数据量较大,须要进行分段传输,否则可能会导致阻塞或缓冲区溢出等问题。
  6. 管道和 FIFO 都是单向的,如果须要双向通信,则须要建设两个管道或 FIFO。

以上,如果感觉对你有帮忙,点个赞再走吧,这样 @知微之见也有更新上来的能源!

也欢送私信我,一起交换!

退出移动版