/***********************************************
管道(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. 旅行青蛙分析(Android篇)

    近期旅行青蛙这款游戏非常的火热,周围的朋友.家人都养了一只小青蛙.看到网上有人说这款游戏可以直接逆向编译,没有加密:所以在搜索相关资料后花了一些时间进行逆向分析与修改.这篇文章里,我将介绍如何获取稀有 ...

  2. 自动检测GD库支持的图像类型

    以下代码通过自动检测GD库支持的图像类型 来写出移直性更好的PHP代码 <?php if(function_exists("imagegif")){ header(" ...

  3. myeclipse-9.0安装svn客户端插件

    SVN插件配置到MyEclipse中的步骤 听语音 | 浏览:20471 | 更新:2015-01-09 10:26 | 标签:myeclipse 1 2 3 4 5 6 7 分步阅读 MyEclip ...

  4. web 中防止sql注入

    public class SqlInject:Page { //检测到注入后的处理方式: 0:仅警告:1:警告+记录:2:警告+自定义错误页面:3:警告+记录+自定义错误页面 ; private co ...

  5. Storm概念学习系列 之数据流模型、Storm数据流模型

    不多说,直接上干货! 数据流模型 数据流模型是由数据流.数据处理任务.数据节点.数据处理任务实例等构成的一种数据模型.本节将介绍的数据流模型如图1所示. 分布式流处理系统由多个数据处理节点(node) ...

  6. 【tf.keras】tf.keras加载AlexNet预训练模型

    目录 从 PyTorch 中导出模型参数 第 0 步:配置环境 第 1 步:安装 MMdnn 第 2 步:得到 PyTorch 保存完整结构和参数的模型(pth 文件) 第 3 步:导出 PyTorc ...

  7. Dedecms标签arclistsg调用单表模型出错的解决方法

    使用arclistsg标签调用分类信息等单表模型出错提示Column 'id' in where clause is ambiguous,  修改文件:include\taglib\arclistsg ...

  8. Rspec基本语法

    引用链接:http://reverocean.iteye.com/blog/1489957 1. describe和context describe和context方法用来组织相关的行为example ...

  9. 《C#高效编程》读书笔记08-推荐使用查询语法而不是循环

    C#语言中并不缺少控制程序流程的结构,for.while.do/while和foreach等都可以做到这一点.但我们还有更好的方式:查询语法(query syntax) 下面这段代码演示了用命令式的方 ...

  10. C#与重构(入门)

    C#与代码重构(入门) 重构(Refactoring)就是通过调整程序代码改善软件的质量.性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性. 单从概念少来理解重构可能很抽象,那么通过下 ...