/***********************************************
管道(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. python之Selenium库的使用

    一  什么是Selenium selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并 ...

  2. angular双向绑定与单向绑定的写法区别

    [ngModel]="manualCode" (ngModelChange)="manualCode=$event;" 等价于下面这样的写法: [(ngMode ...

  3. netstat命令怎么查看端口是否占用

    转自:http://www.ahlinux.com/start/cmd/527.html netstat命令是一个监控TCP IP网络的非常有用的工具,它可以显示路由表.实际的网络连接以及每一个网络接 ...

  4. mybatis批量处理sql

    转载大神 https://www.cnblogs.com/xujingyang/p/8301130.html

  5. The bytes/str dichotomy in Python 3 [transport]

    reference and transporting from: http://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-p ...

  6. stdafx.h预编译头

    转自http://blog.csdn.net/qingkong8832/article/details/6695123 stdafx.h 1名称的英文全称为:Standard Application  ...

  7. Oracle视图,索引,序列

    什么是视图[View] (1)视图是一种虚表 (2)视图建立在已有表的基础上, 视图赖以建立的这些表称为基表(3)向视图提供数据内容的语句为 SELECT 语句,可以将视图理解为存储起来的 SELEC ...

  8. SpringBoot | 第三章:springboot配置详解

    基于springboot的约定优于配置的原则,在多数情况下,启动一个应用时,基本上无需做太多的配置,应用就能正常启动.但在大部分开发环境下,添加额外配置是无所避免的,比如自定义应用端口号(比较在机器比 ...

  9. MySQL三种存储引擎总结

    MySQL三种存储引擎 MyISAM.InnoDB.MEMORY 1.MyISAM MyISAM,3.23.34a前的默认存储引擎. 优缺点 优点 在于占用空间小,处理速度快. 缺点 不支持事务的完整 ...

  10. 《大话设计模式》num01---简单工厂模式

    2017年12月10日 20:13:57 独行侠的守望 阅读数:128更多个人分类: 设计模式编辑版权声明:本文为博主原创文章,转载请注明文章链接. https://blog.csdn.net/xia ...