linux中管道(pipe)一谈
/***********************************************
管道(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)一谈的更多相关文章
- Linux中的pipe(管道)与named pipe(FIFO 命名管道)
catalogue . pipe匿名管道 . named pipe(FIFO)有名管道 1. pipe匿名管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常 ...
- Linux进程间通信 -- 管道(pipe)
前言 进程是一个独立的资源管理单元,不同进程间的资源是独立的,不能在一个进程中访问另一个进程的用户空间和内存空间.但是,进程不是孤立的,不同进程之间需要信息的交互和状态的传递,因此需要进程间数据 ...
- Linux进程间通信—管道
Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...
- Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...
- Linux 进程间通信之管道(pipe),(fifo)
无名管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信: 定义函数: int pipe(int f ...
- Linux学习笔记——管道PIPE
管道:当从一个进程连接数据流到另一个进程时,使用术语管道(pipe).# include <unistd.h> int pipe(int filedes[2]); //创建管道 pipe( ...
- 【Linux 应用编程】进程管理 - 进程间通信IPC之管道 pipe 和 FIFO
IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
随机推荐
- 修改profile出错后的补救
修改profile出错后的补救,谢天谢地export命令还能用 今天在鼓捣centOS的时候,一不小心把用户配置文件profile给改错啦.重启之后进不了图形界面,终端里的命令也有大半不好使啦. 我试 ...
- putty提示Network error:Software caused connection abort
在 sshd host 的 /etc/ssh/sshd_config 设定: TCPKeepAlive yes,和将LoginGraceTime的值设为0,默认为2m,然后使用service sshd ...
- CentOS下ganglia监控部署
第一步:CentOS环境准备 1.yum -y install apr-devel apr-util check-devel cairo-devel pango-devel libxml2-devel ...
- ZC01
1.苏州市住房公积金管理中心 http://www.szgjj.gov.cn/szgjj/ 2.苏州社保 http://www.szsbzx.net.cn:9900/web/website/index ...
- 剑指Offer——数组中的逆序对(归并排序的应用)
蛮力: 遍历数组,对每个元素都往前遍历所有元素,如果有发现比它小的元素,就count++. 最后返回count取模. 结果没问题,但超时哈哈哈,只能过50%. 归并法: 看讨论,知道了这道题的经典 ...
- Java NIO基本使用介绍
NIO主要包括Channel,Buffer,Selector三个核心元素组成. Channel即通道,l和Buffer有好几种类型.下面是JAVA NIO中的一些主要Channel的实现: FileC ...
- Django学习笔记(13)——Django的用户认证(Auth)组件,视图层和QuerySet API
用户认证组件的学习 用户认证是通过取表单数据根数据库对应表存储的值做比对,比对成功就返回一个页面,不成功就重定向到登录页面.我们自己写的话当然也是可以的,只不过多写了几个视图,冗余代码多,当然我们也可 ...
- 1.- Netty设计理念-异步和事件驱动
0. 关键点 a). 非阻塞网络调用,异步方法立即返回 b). 选择器(Selector)使得单一线程就可监控很多连接上的事件. <dependency> <groupId>i ...
- FFmpeg编译i386 OSX 脚本
话不多说, 直接上脚本 #!/bin/sh # directories PLATFORM="OSX" # FFmpeg脚本目录 SOURCE="ffmpeg-2.8.7& ...
- ios MBProgressHUD 使用,及二次封装
MBProgressHUD是一个显示HUD窗口的第三方类库,用于在执行一些后台任务时,在程序中显示一个表示进度的loading视图和两个可选的文本提示的HUD窗口.MBProgressHUD 二次封装 ...