在看过高级的popen函数之后,我们再来看看底层的pipe函数。通过这个函数在两个程序之间传递数据不需要启动一个shell来解释请求的命令。它同时还提供了对读写数据的更多控制。pipe函数的原型如下所示:

#include <unistd.h>
int pipe(int pipefd[2]);

pipe函数的参数是一个由两个整数类型的文件描述符组成的数组的指针。该函数在数组中填上两个新的文件描述符后返回0,如果失败则返回-1并设置errno来表明失败的原因。在Linux手册页(手册的第二部分)中定义了下面一些错误。

❑ EMFILE:进程使用的文件描述符过多。

❑ ENFILE:系统的文件表已满。

❑ EFAULT:文件描述符无效。

两个返回的文件描述符以一种特殊的方式连接起来。写到file_descriptor[1]的所有数据都可以从file_descriptor[0]读回来。数据基于先进先出的原则(通常简写为FIFO)进行处理,这意味着如果你把字节1,2,3写到file_descriptor[1],从file_descriptor[0]读取到的数据也会是1, 2,3。这与栈的处理方式不同,栈采用后进先出的原则,通常简写为LIFO。

特别要注意,这里使用的是文件描述符而不是文件流,所以我们必须用底层的read和write调用来访问数据,而不是用文件流库函数fread和fwrite。

下面的程序pipe1.c用pipe函数来创建一个管道。

实验pipe函数

注意file_pipes数组的用法,它的地址被当作参数传递给pipe函数。

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>#define DEBUG_INFO(format, ...) printf("%s - %d - %s :: "format"\n",__FILE__,__LINE__,__func__ ,##__VA_ARGS__)void test_01(void){int len = 0;int fds_pipes[2];const char some_data[] = "123";const char some_data2[] = "456";char buf[BUFSIZ + 1];memset(buf,0,sizeof(buf));if(pipe(fds_pipes) == 0){len = write(fds_pipes[1],some_data,strlen(some_data));DEBUG_INFO("write len = %d",len);len = read(fds_pipes[0],buf,BUFSIZ);DEBUG_INFO("read len = %d,buf = %s",len,buf);memset(buf,0,sizeof(buf));len = write(fds_pipes[0],some_data2,strlen(some_data2));DEBUG_INFO("write len = %d",len);len = read(fds_pipes[1],buf,BUFSIZ);DEBUG_INFO("read len = %d,buf = %s",len,buf);}else{perror("pipe:");}
}int main(int argc, char**argv){test_01();DEBUG_INFO("hello world");return 0;
}

测试结果:

实验解析

这个程序用数组file_pipes[]中的两个文件描述符创建一个管道。然后它用文件描述符file_pipes[1]向管道中写数据,再从file_pipes[0]读回数据。注意,管道有一些内置的缓存区,它在write和read调用之间保存数据。

如果你尝试用file_descriptor[0]写数据或用file_descriptor[1]读数据,其后果并未在文档中明确定义,所以其行为可能会非常奇怪,并且随着系统的不同,其行为可能会发生变化。在我的系统上,这样的调用将失败并返回-1,这至少能够说明这种错误比较容易发现。

乍看起来,这个使用管道的例子并无特别之处,它做的工作也可以用一个简单的文件完成。管道的真正优势体现在,当你想在两个进程之间传递数据的时候。当程序用fork调用创建新进程时,原先打开的文件描述符仍将保持打开状态。如果在原先的进程中创建一个管道,然后再调用fork创建新进程,我们即可通过管道在两个进程之间传递数据。

实验 跨越fork调用的管道

(1)下面这个程序pipe2.c的开始部分(在调用fork之前的部分)和第一个例子非常相似。

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>#define DEBUG_INFO(format, ...) printf("%s - %d - %s :: "format"\n",__FILE__,__LINE__,__func__ ,##__VA_ARGS__)void test_01(void){int len = 0;int fds_pipes[2];const char some_data[] = "123";const char some_data2[] = "456";pid_t pid;int res;char buf[BUFSIZ + 1];memset(buf,0,sizeof(buf));res = pipe(fds_pipes);if(res != 0){perror("pipe:");return;}pid = fork();if(pid < 0){perror("fork:");return ;}if(pid == 0){len = read(fds_pipes[0],buf,BUFSIZ);DEBUG_INFO("CHILD:pid = %lu,read -- len = %d,buf = %s\n",getpid(),len,buf);len = write(fds_pipes[1],some_data2,BUFSIZ);DEBUG_INFO("CHILD:pid = %lu,write -- len = %d\n",getpid(),len);sleep(1);return;}len = write(fds_pipes[1],some_data,BUFSIZ);DEBUG_INFO("PARENT:pid = %lu,write -- len = %d\n",getpid(),len);len = read(fds_pipes[0],buf,BUFSIZ);DEBUG_INFO("PARENT:pid = %lu,read -- len = %d,buf = %s\n",getpid(),len,buf);sleep(1);
}int main(int argc, char**argv){test_01();DEBUG_INFO("hello world");return 0;
}

测试结果:

在本测试代码中实现了双向通信。

实验解析

这个程序首先用pipe调用创建一个管道,接着用fork调用创建一个新进程。如果fork调用成功,父进程就写数据到管道中,然后父进程开发等待从管道中读数据,子进程从管道中读取数据后,向管道中写数据,然后父进程读到数据。父进程和子进程写数据的时候都使用的文件描述符fds_pipes[1],读数据的时候都使用的文件描述符fds_pipes[0]

CMakeLists.tx 、编译脚本和sftp.json

cmake_minimum_required(VERSION 3.8)
project(myapp)# add_compile_options("-std=c++11")add_executable(popen popen.c)
add_executable(popen2 popen2.c)
add_executable(popen3 popen3.c)
add_executable(popen4 popen4.c)
add_executable(pipe1 pipe1.c)
add_executable(pipe2 pipe2.c)
rm -rf _build_
mkdir _build_ -p
cmake -S ./ -B _build_
make -C _build_
# ./_build_/popen
# ./_build_/popen2
# ./_build_/popen3
# ./_build_/popen4
# ./_build_/pipe1
./_build_/pipe2

sftp.json

{"name": "My Server","host": "192.168.31.138","protocol": "sftp","port": 22,"username": "lkmao","password": "lkmao","remotePath": "/big/work/ipc","uploadOnSave": true,"useTempFile": false,"openSsh": false
}

小结

进程管道:pipe调用相关推荐

  1. 进程间的通信方式(二):管道Pipe和命令管道FIFO

    1.概述 管道是最初的Unix IPC通信,可追溯到1973年的Unix第三版.尽管对于许多操作来说很有用,但它们的根本局限于没有名字,只能由亲缘关系的进程使用.这一点随着FIFO的加入System  ...

  2. pipe 半双工_linux进程间通讯之管道(无名管道pipe)实现全双工双向通讯

    管道是什么: 1. 管道只能用于具备亲缘关系的进程之间通讯. 2.管道是一种单工或者说半双工的通讯方式,传递信息的方向是固定的,只能由一端传递到另外一端. 头文件及函数原型: #include int ...

  3. php管道邮件,php进程通信-PIPE管道通信

    上一篇文章讲到了php进程通信的进程信号通信方法,本文介绍的是有名管道: 管道通信,主要是利用文件,写入以及读取来进行通信的, 通俗来讲,就是A进程在1.txt写入1,B进程读取1.txt,就能读取到 ...

  4. python subprocess pipe_python类库31[进程subprocess与管道pipe]

    修改自: 原文 : Working with Python subprocess - Shells, Processes, Streams, Pipes, Redirects and More 一 程 ...

  5. 无名管道PIPE,进行父子双进程的“双向通信”

    更多资料请点击:我的目录 本篇仅用于记录自己所学知识及应用,代码仍可优化,仅供参考,如果发现有错误的地方,尽管留言于我,谢谢. 本篇记录应用无名管道PIPE,进行父子双进程的"双向通信&qu ...

  6. Linux内核中无名管道pipe和有名管道fifo的分析

    1.管道(pipe) 管道是进程间通信的主要手段之一.一个管道实际上就是个只存在于内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端.管道是一种特殊的文件,它不属于某一种 ...

  7. linux操作系统进程间通信IPC之管道pipe及FIFO

    linux环境下,各进程相互独立,如果想要交换两个进程之间的数据,需要通过内核,在内存中提供一个缓存区,一个进程往缓存区中写数据,一个往缓存区读数据,内核提供的这种机制称为进程间通信(IPC),常见的 ...

  8. 【Linux系统编程学习】匿名管道pipe与有名管道fifo

    此为牛客Linux C++和黑马Linux系统编程课程笔记. 0. 关于进程通信 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不到 ...

  9. Linux学习笔记24——进程管道

    一 管道的作用 通常把一个进程的输出通过管道连接到另一个进程的输入. 二 popen和pclose函数 #include <stdio.h>FILE *popen(const char * ...

最新文章

  1. 收缩 tempdb 数据库
  2. C++报错无效的预处理命令include_无废话--Mac OS, VS Code 搭建c/c++基本开发环境
  3. 3.2.3节:特权级
  4. oracle 三列数值相加,Oracle SQL/PLSQL:按货币拆分和求和值的分层查询
  5. 机器学习入门KNN近邻算法(一)
  6. GitHub 回滚操作
  7. 消息消费要注意的细节
  8. jquery 去除空格
  9. 【强化学习】A3C代码注释版本
  10. 文件另存为时名称会改变_易经:人处在困境时,不要焦虑,改变固定习惯,就会迎来转机...
  11. LintCode刷题笔记-- BackpackIII
  12. jquery.dataTables列中内容居中问题?求解?
  13. c++ 输出string_来讲讲Java中String 类的知识点
  14. ASP.NET中的HttpWorkerRequest对像及其应用
  15. coolnbsp;sensor/image/videonbsp;technbsp;cou…
  16. 图片怎样调整分辨率?如何在线修改分辨率?
  17. 本题要求编写程序,输出整数152的个位数字、十位数字和百位数字的值。
  18. bat批量修改文件后缀
  19. [水]关于web地图
  20. resnet_unetpp

热门文章

  1. 官方微博运营之道的一点总结
  2. 记一次为学校流浪猫开发的小程序——航海之猫
  3. 基于JSP的网上服装销售系统
  4. 【详解】计算机视觉之目标检测
  5. 苹果发家秘决:滚雪球
  6. Cisco单SSID多VLAN的设置
  7. 【Springboot】Json转换工具
  8. 4年前的最佳小说回顾
  9. 数字调制系统工作原理_无人值守道闸系统的工作原理
  10. poi版本不兼容问题解决