/***********************************************
管道(pipe)是Linux上进程间通信的一种方式,其是半双工(数据流只能在一个方向上流动(还需要经过内核),及要么是接收,要么是发送),并且只能在父子进程 或 具有公共祖先的两个子进程间通信。
管道(pipe)一般是在调用fork函数之前调用pipe函数创建,这样的话,fork后子进程将得到父进程的两个管道描述符副本(相当于调用了两次dup)。 /***********************************************
相关函数:
#include <unistd.h>
int pipe(int fd[2])
返回值:成功返回0,失败返回-1
***********************************************/
注意: 函数执行成功后为参数返回两个描述符,fd[0]为读而打 开,fd[1]为写而打开 很多系统在stat结构体st_size成员中储存管道中可用于读写字节数。但这是不可移植的。(对于struct stat不了解的请百度) 使用管道有几点注意事项:
1.当读(read)一个写(write)端已经关闭的管道,程序(read)将读完管道中所有数据后返回0。
2.当写(write)一个读(write)端已经关闭的管道,将产SIGPIP信号,程序(write)返回-1,并将错误码置为EPIPE
3.如果管道中数据为空,则(read)将永久堵塞直到有数据或写(write)端关闭。
4.如果管道已被数据填满,则(write)将会堵塞直到管道中有空与空间 或 写端(read)关闭,(管道容量可用fpathconf函数得到,使用_PC_PIPE_BUF参数)。
***********************************************/
实例1:
使用管道实现 ls -l | wc -c 操作 分析:
执行ls -l后其结果将会被打印到终端(即使用到STDOUT_FILENO)标准输出,wc -c(统计单词数量)是从标准输入中得到内容(即使用到STDIN_FILENO)然后进行统计。 思路:
子进程中调用exec函数族执行ls -l命令,并调用dup2函数将子进程中的fd[1]描述符复制为标准输出(STDOUT_FILENO),这用的话,但向标准输出中写数据是就等同于向管道中写数据。
对于父进程则调用exec函数族执行wc -c命令,然后调用dup2将fd[0]复制为标准输入, 实例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> int main(int argc, char **argv)
{
pid_t pid;
int fd[2]; /**创建管道**/
if (pipe(fd) < 0) {
perror("pipe error");
return EXIT_FAILURE;
} /**调用fork函数创建子进程**/
if ((pid = fork()) < 0) {
perror("fork error");
return EXIT_FAILURE;
} else if (0 == pid) {
close(fd[0]); /**关闭不必要的描述符**/
if (fd[1] != STDOUT_FILENO) {
if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
perror("dup2 error to stdout");
return EXIT_FAILURE;
}
close(fd[1]);
} execlp("ls", "ls", "-l", NULL);
exit(EXIT_SUCCESS);
} //sleep(2);
close(fd[1]);
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
perror("dup2 error to stdin");
return EXIT_FAILURE;
}
close(fd[0]);
} execlp("wc", "wc", "-c", NULL); /**回收子进程的退出状态,避免产生僵死进程**/
if (waitpid(pid, NULL, 0) < 0) {
perror("waitpid error");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
实例2:
实现分页功能 即more命令 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h> #define PAGE "/bin/more"
#define MAXLINE 1024 int main(int argc, char **argv)
{
pid_t pid;
int fd[2];
char line[MAXLINE];
char *page = NULL, *temp = NULL, *arg = NULL;
FILE *fp = NULL; if (argc != 2) {
printf("Usage: %s <filename>\n", argv[0]);
return EXIT_FAILURE;
} if ((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen error");
return EXIT_FAILURE;
} if (pipe(fd) < 0) {
perror("pipe error");
return EXIT_FAILURE;
} if ((pid = fork()) < 0) {
perror("fork error");
return EXIT_FAILURE;
} else if (0 == pid) {
close(fd[0]); int len;
while (fgets(line, MAXLINE, fp) != NULL) {
len = strlen(line); int offset = 0, n = 0;
while (len) {
n = write(fd[1], line+offset, len);
offset += n;
len -= n;
}
} if (ferror(fp)) {
perror("fgets errro");
return EXIT_FAILURE;
} fclose(fp);
close(fd[1]);
} close(fd[1]); if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
perror("dup2 error to stdin");
return EXIT_FAILURE;
} close(fd[0]);
} /***得到PAGE对应的环境参数***/
if ((page = getenv("PAGE")) != NULL) {
arg = page;
} else {
arg = PAGE;
} /**
*strrchr函数判断'\'字符,
*在arg字符串中最后一次出现的位置
**/
if ((temp = strrchr(arg, '/')) != NULL) {
temp++;
} else {
temp = arg;
} execl(arg, temp, NULL); if (waitpid(pid, NULL, 0) < 0) {
perror("waitpid error");
return EXIT_FAILURE;
} return EXIT_SUCCESS;
}

linux中管道(pipe)一谈的更多相关文章

  1. Linux中的pipe(管道)与named pipe(FIFO 命名管道)

    catalogue . pipe匿名管道 . named pipe(FIFO)有名管道 1. pipe匿名管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常 ...

  2. Linux进程间通信 -- 管道(pipe)

    前言    进程是一个独立的资源管理单元,不同进程间的资源是独立的,不能在一个进程中访问另一个进程的用户空间和内存空间.但是,进程不是孤立的,不同进程之间需要信息的交互和状态的传递,因此需要进程间数据 ...

  3. Linux进程间通信—管道

    Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

  4. Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

    整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...

  5. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  6. Linux 进程间通信之管道(pipe),(fifo)

     无名管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信: 定义函数: int pipe(int f ...

  7. Linux学习笔记——管道PIPE

    管道:当从一个进程连接数据流到另一个进程时,使用术语管道(pipe).# include <unistd.h> int pipe(int filedes[2]); //创建管道 pipe( ...

  8. 【Linux 应用编程】进程管理 - 进程间通信IPC之管道 pipe 和 FIFO

    IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...

  9. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

随机推荐

  1. oracle数据库的导入导出命令

    说明:将以下命令复制到cmd命令行中运行即可,file代表文件名数据导入imp zzbweb/zzbweb@orcl file=e:\zzbweb.dmp fromuser=zzbweb touser ...

  2. github:当你想要使用VSCODE开心提交代码时,出现Git:git@github.com:Permission denied(publickey)解决方案

    当你想要使用VSCODE开心提交代码时,出现Git:git@github.com:Permission denied(publickey)弹框 图片: 原因:电脑公钥(publickey)未添加至gi ...

  3. js index of()用法

    含义: indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置.(工作中常用) 提示和注释: 注释:indexOf() 方法对大小写敏感! 注释:如果要检索的字符串值没有出现,则该方 ...

  4. 树的计数 Prufer序列+Cayley公式

    先安利一发.让我秒懂.. 第一次讲这个是在寒假...然而当时秦神太巨了导致我这个蒟蒻自闭+颓废...早就忘了这个东西了... 结果今天老师留的题中有两道这种的:Luogu P4981 P4430 然后 ...

  5. UVa11093

    //当汽车从第i个加油站到第j个加油站无法继续走下去的时候,这时候[i,j]区间的所有加油站都无法作为起点,因为当我们到第k个加油站的时候,起码是带着>=0的油去的,现在不带油直接从第k个开始肯 ...

  6. 1100 Mars Numbers(20 分)

    People on Mars count their numbers with base 13: Zero on Earth is called "tret" on Mars. T ...

  7. Linux--2 Linux之文档与目录结构、shell基本命令

    一.Linux之文档与目录结构 1.Linux之文档与目录结构 Linux目录结构的组织形式和Windows有很大的不同.Linux没有“盘(如C盘.D盘.E盘)”的概念,而是建立一个根"/ ...

  8. spock和junit测试报告

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  9. 成功安装tesserocr

    首先按照官网的操作,出现了下面的错误. 错误描述: x86_64-linux-gnu-gcc: error trying to exec 'cc1plus': execvp: 没有那个文件或目录 er ...

  10. Gym 100971B Derangement

    要求改换序列,使得没有位置是a[i] == i成立.输出最小要换的步数 首先把a[i] == i的位置记录起来,然后两两互相换就可以了. 对于是奇数的情况,和它前一个换或者后一个换就可以,(注意前一个 ...