linux 标准流管道 popen 源码理解
来源:互联网 发布:石家庄企业办公软件 编辑:程序博客网 时间:2024/05/10 13:57
标准流管道popen、pclose函数说明:
#include <stdio.h>FILE *popen(const char *command, const char *type)
返回值:若成功,返回文件流指针;若出错,返回-1
参数说明:
- Command:指向的是一个以 null 结束符结尾的字符串,这个字符串包含一个 shell 命令,并被送到/bin/sh 以-c 参数执行,即由 shell 来执行
- type:
- ”r”: 文件指针连接到 command 的标准输出
- “w” :文件指针连接到 command 的标准输入
#include <stdio.h>int pclose(FILE *stream)
返回值:若成功,返回 popen 中执行命令的终止状态;若出错,返回-1
参数说明:
- stream:要关闭的文件流
popen函数其实是对管道操作的一些包装,所完成的工作有以下几步:
- 创建一个管道。
- fork 一个子进程。
- 在父子进程中关闭不需要的文件描述符。
- 执行 exec 函数族调用。
- 执行函数中所指定的命令。
可以对照着Richard Stevens 实现的源码加深理解。
linux popen源码:
/* * popen.c Written by W. Richard Stevens */ #include <sys/wait.h> #include <errno.h> #include <fcntl.h> #include "ourhdr.h" static pid_t *childpid = NULL; /* ptr to array allocated at run-time */ static int maxfd; /* from our open_max(), {Prog openmax} */ #define SHELL "/bin/sh" FILE * popen(const char *cmdstring, const char *type) { int i, pfd[2]; pid_t pid; FILE *fp; /* only allow "r" or "w" */ if ((type[0] != 'r' && type[0] != 'w') || type[1] != 0) { errno = EINVAL; /* required by POSIX.2 */ return(NULL); } if (childpid == NULL) { /* first time through */ /* allocate zeroed out array for child pids */ maxfd = open_max(); if ( (childpid = calloc(maxfd, sizeof(pid_t))) == NULL) return(NULL); } if (pipe(pfd) < 0) return(NULL); /* errno set by pipe() */ if ( (pid = fork()) < 0) return(NULL); /* errno set by fork() */ else if (pid == 0) { /* child */ if (*type == 'r') { close(pfd[0]); if (pfd[1] != STDOUT_FILENO) { dup2(pfd[1], STDOUT_FILENO); close(pfd[1]); } } else { close(pfd[1]); if (pfd[0] != STDIN_FILENO) { dup2(pfd[0], STDIN_FILENO); close(pfd[0]); } } /* close all descriptors in childpid[] */ for (i = 0; i < maxfd; i++) if (childpid[ i ] > 0) close(i); execl(SHELL, "sh", "-c", cmdstring, (char *) 0); _exit(127); } /* parent */ if (*type == 'r') { close(pfd[1]); if ( (fp = fdopen(pfd[0], type)) == NULL) return(NULL); } else { close(pfd[0]); if ( (fp = fdopen(pfd[1], type)) == NULL) return(NULL); } childpid[fileno(fp)] = pid; /* remember child pid for this fd */ return(fp); } int pclose(FILE *fp) { int fd, stat; pid_t pid; if (childpid == NULL) return(-1); /* popen() has never been called */ fd = fileno(fp); if ( (pid = childpid[fd]) == 0) return(-1); /* fp wasn't opened by popen() */ childpid[fd] = 0; if (fclose(fp) == EOF) return(-1); while (waitpid(pid, &stat, 0) < 0) if (errno != EINTR) return(-1); /* error other than EINTR from waitpid() */ return(stat); /* return child's termination status */ }
接下来看一个简单的示例程序:
/* popen.c*/#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#define BUFSIZE 1000int main(){ FILE *fp; char *cmd = "ls -al"; char buf[BUFSIZE]; if((fp=popen(cmd,"r"))==NULL) //调用 popen 函数执行命令ls -al perror("popen"); fread( buf, sizeof(char), sizeof(buf),fp); //将刚刚fp指向的文件流读取到buf中 printf("%s",buf); pclose(fp); exit(0);}
实验结果:
ubuntu:~/test/process_test$ gcc popen.c -o popenubuntu:~/test/process_test$ ./popentotal 92drwxr-xr-x 2 4096 Aug 15 16:56 .drwxr-xr-x 19 4096 Aug 15 10:12 ..-rwxr-xr-x 1 12 Aug 15 11:16 file_fork-rwxr-xr-x 1 8784 Aug 15 10:46 fork-rwxr-xr-x 1 8785 Aug 15 10:45 fork2-rwxr--r-- 1 571 Aug 15 11:25 fork2.c-rwxr--r-- 1 469 Aug 15 10:42 fork.c-rwxr-xr-x 1 8890 Aug 15 11:16 open_fork-rwxr--r-- 1 1114 Aug 15 11:25 open_fork.c-rwxr-xr-x 1 8884 Aug 15 16:16 pipe-rwxr--r-- 1 1677 Aug 15 16:16 pipe.c-rwxr-xr-x 1 8683 Aug 15 16:56 popen-rwxr--r-- 1 409 Aug 15 16:56 popen.c
在终端执行shell命令”ls -al”
ubuntu:~/test/process_test$ ls -altotal 92 drwxr-xr-x 2 4096 Aug 15 16:56 .drwxr-xr-x 19 4096 Aug 15 10:12 ..-rwxr-xr-x 1 12 Aug 15 11:16 file_fork-rwxr-xr-x 1 8784 Aug 15 10:46 fork-rwxr-xr-x 1 8785 Aug 15 10:45 fork2-rwxr--r-- 1 571 Aug 15 11:25 fork2.c-rwxr--r-- 1 469 Aug 15 10:42 fork.c-rwxr-xr-x 1 8890 Aug 15 11:16 open_fork-rwxr--r-- 1 1114 Aug 15 11:25 open_fork.c-rwxr-xr-x 1 8884 Aug 15 16:16 pipe-rwxr--r-- 1 1677 Aug 15 16:16 pipe.c-rwxr-xr-x 1 8683 Aug 15 16:56 popen-rwxr--r-- 1 409 Aug 15 16:56 popen.c
实验结果跟在终端执行shell命令是一样的。理解源码之后,对popen理解也更加深刻,在不同场景中运用也更加自如。
阅读全文
0 0
- linux 标准流管道 popen 源码理解
- 进程间通信---标准流管道
- linux进程通信(二)-------标准流管道和命名管道
- 流管道
- Linux 目录流管理
- java io流管道流
- Linux 文件流与目录流管理
- suricata 3.1 源码分析16 (流管理1)
- suricata 3.1 源码分析17 (流管理2)
- wireshark源码探索No.5---wireshark的流管理
- linux popen函数
- Linux c的popen()
- Linux popen()函数使用
- linux popen函数
- linux popen函数
- linux popen函数
- Linux popen用法
- Linux popen用法
- TCP对SACK的处理以及乱序的处理细节
- 面向过程和面向对象
- linux sar命令
- 改进版简易卖票系统,线程操作
- 【游戏跨场景寻路】基于as3语言的游戏地图跨场景寻路功能的实现
- linux 标准流管道 popen 源码理解
- Spring Ioc创建源码分析
- HDU 4027 Can you answer these queries?——其实是点更新的区间更新线段树
- C
- HDU
- 大端小端测试代码
- D
- hdu_2137_字符串旋转
- dpkg 被中断问题解决方法