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

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. 不要忽视Web编程中的小细节

    概述:长时间以来,我们创造了某些在构造和范围内用以提升网站易用性的约定和实践.然后在我们进行web编程的时候总有一些疏忽和纰漏.这里总结了一些web编程时容易出现的小错误,并给出了相应的补救方法,希望 ...

  2. python实现王者荣耀英图片收集

    一个python写的小爬虫项目,爬虫相关的很容易写,关键是怎么找到爬取图片的位置. 图片位置分析 hero_list_url = 'http://pvp.qq.com/web201605/js/her ...

  3. 源码分析ConcurrentHashMap

    ConcurrentHashMap 1.7 segment分段锁 1.8 CAS 红黑树

  4. 1160: sundari && Shortest path HDU - 4479

    http://gdutcode.sinaapp.com/problem.php?id=1160 http://acm.hdu.edu.cn/showproblem.php?pid=4479 35 51 ...

  5. HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护

    给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个. 首先,dfs一下,处理出L[i], R[i]表示d ...

  6. (转)CentOS 7常见的基础命令和配置

    CentOS 7常见的基础命令和配置 原文:http://blog.51cto.com/hujiangtao/1973566 管理服务 命令格式:systemctl COMMAND name.serv ...

  7. Spring AOP——Spring 中面向切面编程

    前面两篇文章记录了 Spring IOC 的相关知识,本文记录 Spring 中的另一特性 AOP 相关知识. 部分参考资料: <Spring实战(第4版)> <轻量级 JavaEE ...

  8. 多个activity之间的数据共享

    Activity之间的数据共享问题起初一看并没有那么纠结,原因在于两点,一来两个Activity之间可以通过回传的方式进行数据的共享,而哪怕是多个Activity之间,也可以通过静态类进行数据的共享. ...

  9. ArcGIS API for JavaScript开发初探——HelloMap

    1.前言 在开始ArcGIS API for JavaScript开发之前我们需要了解一些基本的知识: 1.开发工具选什么? 前端技术的开发工具选择是一个仁者见仁智者见智的问题,有人喜欢Hbuilde ...

  10. 【作业留存】根据IATF框架,设计的一种中小型企业安全拓扑