linux系统——管道

linux系统——管道本文深入探讨了 Linux 中的管道通信机制 包括匿名管道的 popen 和 pipe 调用 以及命名管道 FIFO 的创建和使用

大家好,欢迎来到IT知识分享网。

一、管道基础

二、进程匿名管道——poen调用

1、相关函数

linux系统——管道

2、poen的实现原理

3、popen例子

在一个popen调用中使用了cat程序、wc程序、shell程序,并进行了异常重定向,但是只能看到最终popen调用的输出结果

#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, '\0', sizeof(buffer)); read_fp = popen("cat popen*.c | wc -l", "r");//以读的方式打开管道,此时调用进程可通过fread()读取调用线程的数据 //因为不知道要读取的数据的大小,因此循环使用fread函数进行读取,直到fread函数返回的读取的数据为0 if (read_fp != NULL) { chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); while (chars_read > 0) { buffer[chars_read - 1] = '\0'; printf("Reading:-\n %s\n", buffer); chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); } pclose(read_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } 

三、进程匿名管道——pipe调用

比popen调用更底层,对读写数据更多控制

1、相关函数

linux系统——管道

2、pipe例子——单进程例子下的管道

#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; memset(buffer, '\0', sizeof(buffer)); if (pipe(file_pipes) == 0) { data_processed = write(file_pipes[1], some_data, strlen(some_data));//从1端写数据 printf("Wrote %d bytes\n", data_processed); data_processed = read(file_pipes[0], buffer, BUFSIZ);//从0端读数据,数据符合先进先出的FIFO规则 printf("Read %d bytes: %s\n", data_processed, buffer); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } 

3、pipe管道——主进程和分离进程间的管道

#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; pid_t fork_result; memset(buffer, '\0', sizeof(buffer)); if (pipe(file_pipes) == 0) {//主进程中创建管道 fork_result = fork();//创建一个分离的子进程 if (fork_result == -1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } // We've made sure the fork worked, so if fork_result equals zero, we're in the child process. if (fork_result == 0) {//子进程中动作——读 data_processed = read(file_pipes[0], buffer, BUFSIZ); printf("Read %d bytes: %s\n", data_processed, buffer); exit(EXIT_SUCCESS); } // Otherwise, we must be the parent process. else {//父进程中动作——写 data_processed = write(file_pipes[1], some_data, strlen(some_data)); printf("Wrote %d bytes\n", data_processed); } } exit(EXIT_SUCCESS); } 

4、pipe管道——主进程和其他进程之间的管道

#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; pid_t fork_result; memset(buffer, '\0', sizeof(buffer)); if (pipe(file_pipes) == 0) {//程序1的主进程创建管道 fork_result = fork(); if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == 0) {//已经在由fork创建的相对独立的进程内,此时再调用execl函数替换进程为Ppip4 sprintf(buffer, "%d", file_pipes[0]); (void)execl("pipe4", "pipe4", buffer, (char *)0);//子进程内调用execl函数创建一个子进程的复制进程 exit(EXIT_FAILURE); } else { data_processed = write(file_pipes[1], some_data, strlen(some_data));//程序1的父进程动作,向管道写数据 printf("%d - wrote %d bytes\n", getpid(), data_processed); } } exit(EXIT_SUCCESS); } 

/程序2——消费者 程序名:pipe4/

// The 'consumer' program, pipe4.c, that reads the data is much simpler. #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { int data_processed; char buffer[BUFSIZ + 1]; int file_descriptor; memset(buffer, '\0', sizeof(buffer)); sscanf(argv[1], "%d", &file_descriptor); data_processed = read(file_descriptor, buffer, BUFSIZ);//程序2的动作,从管道中读数据 printf("%d - read %d bytes: %s\n", getpid(), data_processed, buffer); exit(EXIT_SUCCESS); } 

5、管道关闭后的读操作

linux系统——管道linux系统——管道

6、把管道作为标准输入和标准输出

linux系统——管道在这里插入图片描述

#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; pid_t fork_result; if (pipe(file_pipes) == 0) {//创建管道,父子进程共4个文件描述符,t file_pipes[2]各有一份副本在父子进程 fork_result = fork();//创建分离进程 if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == (pid_t)0) {//在子进程中 close(0);//关闭标准输入 dup(file_pipes[0]);//打开一个新的文件描述符,该dup()函数总取最小的可用值,因此管道输入——》标准输入 close(file_pipes[0]);//关闭管道原来用来读取的数据的文件描述 close(file_pipes[1]);//因为子进程中不会向管道写输入,故关闭 execlp("od", "od", "-c", (char *)0); exit(EXIT_FAILURE); } else {//现在在父进程中 close(file_pipes[0]);//父进程不会从管道读取数据,因此关闭管道读取端 data_processed = write(file_pipes[1], some_data, strlen(some_data)); close(file_pipes[1]);//父进程向管道写完数据后,关闭管道写入端 printf("%d - wrote %d bytes\n", (int)getpid(), data_processed); } } exit(EXIT_SUCCESS); } 

四、命名管道——FIFO

主要用在不相关的进程间交换数据

1、创建FIFO文件

使用函数创建的是一个特殊的文件,文件的模式受umask影响mode_t mode=0777,umask=0022,则创建的特殊文件的权限值为755

2、访问FIFO文件

linux系统——管道
例子如下:
程序中没有删除创建的文件,时因为我们无法知道是否有其他程序正在使用它

// Let's start with the header files, a #define and the check that the correct number // of command-line arguments have been supplied. #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "/tmp/my_fifo" int main(int argc, char *argv[]) { int res; int open_mode = 0; int i; if (argc < 2) { fprintf(stderr, "Usage: %s <some combination of\ O_RDONLY O_WRONLY O_NONBLOCK>\n", *argv); exit(EXIT_FAILURE); } // Assuming that the program passed the test, we now set the value of open_mode // from those arguments. for(i = 1; i < argc; i++) { if (strncmp(*++argv, "O_RDONLY", 8) == 0) open_mode |= O_RDONLY; if (strncmp(*argv, "O_WRONLY", 8) == 0) open_mode |= O_WRONLY; if (strncmp(*argv, "O_NONBLOCK", 10) == 0) open_mode |= O_NONBLOCK; } // We now check whether the FIFO exists and create it if necessary. // Then the FIFO is opened and output given to that effect while the program // catches forty winks. Last of all, the FIFO is closed. if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0777);//创建命令管道文件 if (res != 0) { fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO\n", getpid()); res = open(FIFO_NAME, open_mode);//打开命名管道文件 printf("Process %d result %d\n", getpid(), res); sleep(5); if (res != -1) (void)close(res);//关闭命名管道文件 printf("Process %d finished\n", getpid()); exit(EXIT_SUCCESS); } 使用方式1: //以读的方式打开命名管道,open调用将阻塞,直到另一个进程已写方式打开命名管道 $./fifo2 O_RDONLY & //以写的方式打开命名管道,open函数将阻塞,直到另一个进程以读方式打开命名管道 $./fifo2 O_WDONLY 使用方式2: //读方式+标志模式打开管道,open函数不会阻塞 $./fifo2 O_RDONLY O_NONBLOCK & $./fifo2 O_WDONLY 使用方式3: //写方式+标志模式打开管道 $./fifo2 O_WDONLY O_NONBLOCK & $./fifo2 O_RDONLY 

3、O_NONBLOCK对FIFO文件的读写有影响

linux系统——管道在这里插入图片描述
程序例子:

//生产者程序fifo3.c #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "/tmp/my_fifo" #define BUFFER_SIZE PIPE_BUF //定义在limit.h中,在linux和unix系统中一般是4096 #define TEN_MEG (1024 * 1024 * 10) //单次进入管道的长度 int main() { int pipe_fd; int res; int open_mode = O_WRONLY; int bytes_sent = 0; char buffer[BUFFER_SIZE + 1]; if (access(FIFO_NAME, F_OK) == -1) {//检测FIFO管道文件是否存在 res = mkfifo(FIFO_NAME, 0777);//若不存在则创建管道文件 if (res != 0) { fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO O_WRONLY\n", getpid()); pipe_fd = open(FIFO_NAME, open_mode);//以读的方式打开管道,此时阻塞直到有进程以写方式打开管道 printf("Process %d result %d\n", getpid(), pipe_fd); if (pipe_fd != -1) { while(bytes_sent < TEN_MEG) { res = write(pipe_fd, buffer, BUFFER_SIZE); if (res == -1) { fprintf(stderr, "Write error on pipe\n"); exit(EXIT_FAILURE); } bytes_sent += res; } (void)close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finished\n", getpid()); exit(EXIT_SUCCESS); } 
//消费者程序fifo4.c #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "/tmp/my_fifo" #define BUFFER_SIZE PIPE_BUF int main() { int pipe_fd; int res; int open_mode = O_RDONLY; char buffer[BUFFER_SIZE + 1]; int bytes_read = 0; memset(buffer, '\0', sizeof(buffer)); printf("Process %d opening FIFO O_RDONLY\n", getpid()); pipe_fd = open(FIFO_NAME, open_mode);//以读的方式打开管道,阻塞,直到有进程以写的方式打开管道 printf("Process %d result %d\n", getpid(), pipe_fd); if (pipe_fd != -1) { do { res = read(pipe_fd, buffer, BUFFER_SIZE); bytes_read += res; } while (res > 0); (void)close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finished, %d bytes read\n", getpid(), bytes_read); exit(EXIT_SUCCESS); } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/126671.html

(0)
上一篇 2025-09-16 20:26
下一篇 2025-09-16 20:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信