1、管道的定义

管道就是将一个程序的输出和另外一个程序的输入连接起来的单向通道,比如命令: ls -l|more,就建立了一个管道,获取ls -l的输出作为more的输入,数据就沿着管道从管道的左边流到了管道的右边。

实际上内核为进程建立了两个句柄f1和f2,进程通过句柄f1向管道写入数据,同时通过f2从管道读出数据,这里是同一个进程建立了自己的管道

进程间的管道:通过fork出来的子进程,与父进程一样,拥有对同一个管道的读写句柄,但管道是单向的,因此要决定数据流向,如父进程到子进程或者子进程到父进程,那么不需要的句柄就要关闭

2、管道的建立和使用

1)通过pipe()函数建立管道,函数声明是int pipe(fd[2]) ,其中fd[0]用来从管道读,fd[1]向管道写

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = “Hello, world!\n”;
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror(“fork”);
exit(1);
}
if(childpid == 0)
{
/* 子进程关闭管道的读句柄 */
close(fd[0]);
/* 通过写句柄向管道写入信息 */
write(fd[1], string, strlen(string));
_exit(0);
}
else
{
/* 父进程关闭管道的写句柄 */
close(fd[1]);
/* 通过读句柄从管道读出信息 */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf(“Received string: %s”, readbuffer);
}
return(0);
}

  假定了数据流向是子进程到父进程,那么就由子进程写,父进程读,所以子进程要关闭读句柄,而父进程要关闭写句柄

2)使用popen()/pclose()函数,函数声明是FILE* popen(char * command, char *type)

popen()首先调用pipe()建立一个管道,然后用fork()函数建立一个子进程,运行一个shell环节,然后在这个环境中运行"command"参数指定的程序,数据管道流向由type控制,要么为"r"或者为"w",两者取其一,且type只取一个字符,比如"rw",那么只取"r",最后用pclose()关闭即可

#include <stdio.h>
#define MAXSTRS 5
int main(void)
{
int cntr;
FILE *pipe_fp;
char *strings[MAXSTRS] = { "roy", "zixia", "gouki","supper", "mmwan"};
/* 用popen 建立管道 */
if (( pipe_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
/* Processing loop */
for(cntr=0; cntr<MAXSTRS; cntr++)
{
fputs(strings[cntr], pipe_fp);
fputc('\n', pipe_fp);
}
/* 关闭管道 */
pclose(pipe_fp);
return(0);
}

  popen()可以节省源代码,同时还可以在"command"中使用任意合法的shell指令,包括重定向和管道,如下均为合法

popen("ls ~roy", "r");
popen("sort > /tmp/zixia", "w");
popen("sort | uniq | more", "w");

  如下例子为建立了两个管道,一个读管道,一个写管道

#include <stdio.h>
int main(void)
{
FILE *pipein_fp, *pipeout_fp;
char readbuf[80];
/* 用popen 建立一个通向"ls:的读管道*/
if (( pipein_fp = popen("ls", "r")) == NULL)
{
perror("popen");
exit(1);
}
/* 用popen 建立一个通向"sort"的写管道 */
if (( pipeout_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
/* 进程循环 */
while(fgets(readbuf, 80, pipein_fp))
{
fputs(readbuf, pipeout_fp);
} /* 关闭打开的管道 */
pclose(pipein_fp);
pclose(pipeout_fp);
return(0);
}

  

3、tips

1)pipe()调用必须在fork()前

2)及时关闭不需要的管道句柄

3)管道只能实现父子进程之间的通信,若两个进程没有fork()关系,必须考虑其他进程通信方式

Linux网络编程学习(六) ----- 管道(第四章)的更多相关文章

  1. Linux网络编程学习(五) ----- 信号(第四章)

    1.基本概念 进程阻塞: 进程执行条件得不到满足,就自动放弃CPU资源而进入休眠状态,以等待条件满足,当条件满足时,系统就将控制权还给该进程进行未完成的操作 共享资源: 进程间协调使用的系统资源 锁定 ...

  2. Linux网络编程学习计划

    由于网络编程是很重要的一块,自己这一块也比较欠缺,只知道一些皮毛,从今天开始系统学习<Linux网络编程>一书,全书分为十四个章节: 第一章   概论   P1-16 第二章   UNIX ...

  3. Linux网络编程学习路线

    转载自:https://blog.csdn.net/lianghe_work/article 一.网络应用层编程   1.Linux网络编程01——网络协议入门 2.Linux网络编程02——无连接和 ...

  4. Linux网络编程学习(十二) ----- 结语

    该书提前看完了,重点看了第四章和第六章,第七章以后只是大致浏览了一下,如果以后工作中涉及这一块再仔细研究一下,大概花了二十天的样子,主要了解了进程间的通信方式.socket编程以及五种I/O模式,看的 ...

  5. Linux网络编程学习(七) ----- 有名管道(第四章)

    1.什么是有名管道?为什么有了管道还需要有名管道? 有名管道是解决管道不能提供非父子进程间通信的缺陷.管道在Linux系统内部是以文件节点(inode)的形式存在,但由于其对外的不可见性(“无名”性) ...

  6. Linux网络编程学习(十) ----- Socket(第六章)

    前言:由于第五章主要介绍了TCP和UDP协议以及两者的包头的字段以及相应的功能,这里就不介绍了,对着字段看功能就好了,后续开始学习第六章 1.Socket Socket实质上就是提供了通信的端点,每个 ...

  7. Linux网络编程学习(九) ----- 消息队列(第四章)

    1.System V IPC System V中引入的几种新的进程间通信方式,消息队列,信号量和共享内存,统称为System V IPC,其具体实例在内核中是以对象的形式出现的,称为IPC 对象,每个 ...

  8. Linux网络编程学习(十一) ----- 五种I/O模式(第六章)

    1.五种I/O模式是哪几个? 阻塞I/O,非阻塞I/O,I/O多路复用,信号驱动I/O(SIGIO),异步I/O 一般来讲程序进行输入操作有两个步骤,一是等待有数据可读,二是将数据从系统内核中拷贝到程 ...

  9. Linux网络编程学习(八) ----- 文件和记录锁定(第四章)

    1.什么是文件和记录锁定? 文件锁定的是整个文件,而记录锁定只锁定文件的一部分,文件和记录锁分为咨询式锁定和强制锁定 1)咨询式锁定 某个进程对某个文件进行了咨询式锁定,其他想访问该文件的进程将会被操 ...

随机推荐

  1. 基于Verilog的按键检测实验

    一.模块框图及基本思路 detect_module:检测按键输入脚的电平边沿变化 delay_10ms_module:延时消抖,输出按键有效信号 debounce_module:前两个模块的组合模块 ...

  2. Python 精进版SVIP版通过队列实现一个生产者消费者模型

    import time from multiprocessing import Process,Queue,JoinableQueue #生产者 def producer(q): for i in r ...

  3. 自动化测试-7.selenium定位一组对象

    前言 前面的几篇都是讲如何定位一个元素,有时候一个页面上有多个对象需要操作,如果一个个去定位的话,比较繁琐,这时候就可以定位一组对象. webdriver 提供了定位一组元素的方法,跟前面八种定位方式 ...

  4. C/C++ 宏技巧

    1. C 也可以模板化 #define DEFINE_ARRAY_TYPE(array_type_, element_type_) \ static inline int array_type_ ## ...

  5. python trie

    Trie 库 https://github.com/pytries/marisa-trie/blob/master/docs/tutorial.rst http://marisa-trie.readt ...

  6. day 12

    一,什么是装饰器? 装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用场景:比如插入日志,性能测试,事 ...

  7. 第三章 C#程序结构[3.2 选择结构的应用(Windows窗体应用程序)(四)]

    [案例]设计一个顾客选购商品的系统.其中,顾客身份有两类,一类是VIP,另一类是普通会员:商品种类有3种.分别是上衣.裤子和鞋子.其中,VIP享受8折优惠和商店赠送的礼品,而普通会员都不享受.单击[确 ...

  8. Linux之cp、rm、mv

    cp.rm.mv 命令功能: 复制文件或目录 命令格式: cp [OPTION]... [-T] SOURCE DEST cp [OPTION]... SOURCE... DIRECTORY cp [ ...

  9. ROS下利用realsense采集RGBD图像合成点云

    摘要:在ROS kinetic下,利用realsense D435深度相机采集校准的RGBD图片,合成点云,在rviz中查看点云,最后保存成pcd文件. 一. 各种bug 代码编译成功后,打开rviz ...

  10. 报错:Exception in thread "main" com.typesafe.config.ConfigException$UnresolvedSubstitution

    报错现象: 报错原因: pom文件中的jar包太高,可以降低jar包的版本号. 报错解决: 我将2.11换成了2.10,即可解决. <dependency> <groupId> ...