`

linux c学习笔记----管道文件(pipe,popen,mkfifo,pclose,dup2)

阅读更多

 

pipe(建立管道) 


相关函数
mkfifo,popen,read,write,fork
表头文件
#include<unistd.h>
定义函数
int pipe(int filedes[2]);
函数说明
pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。
返回值
若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码
EMFILE 进程已用完文件描述词最大量。
ENFILE 系统已无文件描述词可用。
EFAULT 参数filedes数组地址不合法。
范例
/* 父进程借管道将字符串“hello!\n”传给子进程并显示*/
#include <unistd.h>
main()
{
int filedes[2];
char buffer[80];
pipe(filedes);
if(fork()>0){
/* 父进程*/
char s[ ] = “hello!\n”;
write(filedes[1],s,sizeof(s));
}
else{
/*子进程*/
read(filedes[0],buffer,80);
printf(“%s”,buffer);
}
}
执行
hello!

 实例:

 

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFFER 255

int main(int argc, char **argv) {
    char buffer[BUFFER + 1];
    int fd[2];
    if (argc != 2) {
        fprintf(stderr, "Usage:%s string\n\a", argv[0]);
        exit(1);
    }
    if (pipe(fd) != 0) {
        fprintf(stderr, "Pipe Error:%s\n\a", strerror(errno));
        exit(1);
    }
    if (fork() == 0) {
        close(fd[0]);
        printf("Child[%d] Write to pipe\n\a", getpid());
        snprintf(buffer, BUFFER, "%s", argv[1]);
        write(fd[1], buffer, strlen(buffer));
        printf("Child[%d] Quit\n\a", getpid());
        exit(0);
    } else {
        close(fd[1]);
        printf("Parent[%d] Read from pipe\n\a", getpid());
        memset(buffer, '\0', BUFFER + 1);
        read(fd[0], buffer, BUFFER);
        printf("Parent[%d] Read:%s\n", getpid(), buffer);
        exit(1);
    }
}

 

popen(建立管道I/O)

 




相关函数
pipe,mkfifo,pclose,fork,system,fopen
表头文件
#include<stdio.h>
定义函数
FILE * popen( const char * command,const char * type);
函数说明
popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外。
返回值
若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
错误代码
EINVAL参数type不合法。
注意事项
在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。
范例
#include<stdio.h>
main()
{
FILE * fp;
char buffer[80];
fp=popen(“cat /etc/passwd”,”r”);
fgets(buffer,sizeof(buffer),fp);
printf(“%s”,buffer);
pclose(fp);
}
执行
root :x:0 0: root: /root: /bin/bash

 

 

mkfifo(建立具名管道)

 


相关函数
pipe,popen,open,umask
表头文件
#include<sys/types.h>
#include<sys/stat.h>
定义函数
int mkfifo(const char * pathname,mode_t mode);
函数说明
mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。

返回值
若成功则返回0,否则返回-1,错误原因存于errno中。
错误代码
EACCESS 参数pathname所指定的目录路径无可执行的权限
EEXIST 参数pathname所指定的文件已存在。
ENAMETOOLONG 参数pathname的路径名称太长。
ENOENT 参数pathname包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
EROFS 参数pathname指定的文件存在于只读文件系统内。
范例
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
char *FIFO = "/tmp/my_fifo";
main()
{
char buffer[80];
int fd;
unlink(FIFO);
mkfifo(FIFO,0666);
if(fork()>0){
char s[ ] = “hello!\n”;
fd = open (FIFO,O_WRONLY);
write(fd,s,sizeof(s));
close(fd);
}
else{
fd= open(FIFO,O_RDONLY);
read(fd,buffer,80);
printf(“%s”,buffer);
close(fd);
}
}
 
执行
hello!

 

 

 

pclose(关闭管道I/O)

相关函数
popen
表头文件
#include<stdio.h>
定义函数
int pclose(FILE * stream);
函数说明
pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针。
返回值
返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。
错误代码
ECHILD pclose()无法取得子进程的结束状态。
范例
参考popen()。

 

 

为了实现重定向操作,我们需要调用另外一个函数dup2

 

dup2(复制文件描述词)

 


相关函数
open,close,fcntl,dup
表头文件
#include<unistd.h>
定义函数
int dup2(int odlfd,int newfd);
函数说明
dup2()用来复制参数oldfd所指的文件描述词,并将它拷贝至参数newfd后一块返回。若参数newfd为一已打开的文件描述词,则newfd所指的文件会先被关闭。dup2()所复制的文件描述词,与原来的文件描述词共享各种文件状态,详情可参考dup()。
返回值
当复制成功时,则返回最小及尚未使用的文件描述词。若有错误则返回-1,errno会存放错误代码。
附加说明
dup2()相当于调用fcntl(oldfd,F_DUPFD,newfd);请参考fcntl()。
错误代码
EBADF 参数fd 非有效的文件描述词,或该文件已关闭

实例:

 

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFER_SIZE 1024

int main(int argc, char **argv) {
    int fd;
    char buffer[BUFFER_SIZE];
    if (argc != 2) {
        fprintf(stderr, "Usage:%s outfilename\n\a", argv[0]);
        exit(1);
    }
    if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) {
        fprintf(stderr, "Open %s Error:%s\n\a", argv[1], strerror(errno));
        exit(1);
    }
    if (dup2(fd, STDOUT_FILENO) == -1) {
        fprintf(stderr, "Redirect Standard Out Error:%s\n\a", strerror(errno));
        exit(1);
    }
    fprintf(stderr, "Now,please input string");
    fprintf(stderr, "(To quit use CTRL+D)\n");
    while (1) {
        fgets(buffer, BUFFER_SIZE, stdin);
        if (feof(stdin))break;
        write(STDOUT_FILENO, buffer, strlen(buffer));
    }exit(0)}
分享到:
评论

相关推荐

    Linux系统中popen函数的缺陷与改造方案.pdf

    其原因是 popen 函数内部将管道文件设置成了阻塞的性质。 为了解决这两个缺陷,我们需要对 popen 函数进行改造。改造后的函数 mypopen 实现见程序段 2。 mypopen 函数的改造实现主要包括以下几点: 1. 能够将标准...

    linux系统编程笔记

    - dup和dup2函数用于复制文件描述符。 - select函数用于等待一组文件描述符中的任何一个变得可读、可写或发生异常。 - ioctl函数提供对设备的控制操作。 4. 文件目录及其I/O - 包含打开关闭文件、读写文件、...

    linux shell窗口工具-qt5源码

    在C语言中,`pipe()`函数用于创建一个管道,并返回两个文件描述符,一个用于写入(parent进程),另一个用于读取(child进程)。在shell工具中,你可以使用管道将命令的输出传递给另一个命令,实现命令链的功能,如`...

    如何解决fgets读取popen内容阻塞的问题

    该问题的解决方案涉及到 Linux 操作系统中进程间通信、管道和文件指针的使用。 在 Linux 系统中,一个父进程可以通过 fork 和 exec 函数族来创建一个子进程,以执行特定的任务(command)。也可以使用 popen 函数来...

    LINUX进程间通信:PIPE与FIFO - 山 人 - 博客园1

    除了直接使用系统调用外,C语言的标准库还提供了`popen()`和`pclose()`函数,用于创建一个管道并启动另一个进程,该进程从该管道读出标准输入或将标准输出写入该管道。这些函数简化了管道的创建和使用过程。 **...

    linux popen函数

    在Linux系统中,`popen`函数是一个非常实用的C语言标准库函数,它允许程序以进程间通信(IPC,Inter-Process Communication)的方式与另一个命令或者程序进行交互。`popen`函数在`stdio.h`头文件中定义,它的主要...

    linux C程序中获取shell脚本输出(如获取system命令输出)

    2. **执行命令**:使用`popen()`函数执行`ls -l`命令,这里的`"r"`表示以只读模式打开管道,即`popen()`函数返回的是一个指向管道输入端的流。 3. **读取输出**:通过`fread()`函数从`stream`中读取数据,并存储到`...

    Linux下使用popen()执行shell命令.docx

    Linux 下使用 popen() 执行 shell 命令 在 Linux 操作系统中,popen() 函数是一个强大的工具,允许开发者执行 shell 命令并获取其输出结果。popen() 函数通过创建一个管道,调用 fork() 产生一个子进程,执行一个 ...

    tcps.zip_linux 远程控制_popen

    在这个场景中,我们看到的`tcps.zip_linux 远程控制_popen`主题是关于在Linux环境下,利用管道(pipe)和`popen`函数来实现远程控制功能。 首先,我们要理解`popen`函数的工作原理。`popen`函数创建一个新的进程,...

    重新实现popen和system函数

    总之,重新实现 `popen` 和 `system` 函数涉及多个系统调用的组合,包括 `fork`, `pipe`, `dup2`, `exec`, `wait` 等,以及对文件描述符的管理。这样做不仅可以定制功能,还可以优化资源使用,提升程序的安全性和...

    Linux C 常用库函数手册

    Linux C常用库函数手册涵盖了Linux环境下C编程中经常用到的库函数,这些函数可以分为不同的类别,每种类别下包含了多个特定功能的函数。以下是对这些库函数按照类别和功能进行的详细解读: 1. 用户组篇 这部分涉及...

    GNU_LINUX 系统编程笔记.pdf

    以上是基于《GNU/Linux系统编程笔记》中的知识点总结,涵盖了错误处理、I/O操作、文件目录管理、进程控制、线程、内存管理、IPC以及守护进程设计等关键领域,对于深入理解Linux系统编程有重要价值。

    Linux系统编程学习笔记

    ### Linux系统编程学习笔记 #### 一、IO **1.1 标准I/O (stdio)** - **fopen/fclose**: `fopen` 用于打开或创建一个文件,并返回一个指向该文件的 `FILE *` 类型的指针。`fclose` 用于关闭一个已经打开的文件。...

    操作系统实验报告进程的管道及消息通信.doc

    - 利用 `popen()` 和 `pclose()` 实现命令行工具与管道文件之间的交互。 - 例如,通过 `chcase` 程序将文本文件中的小写字母转换为大写。 - 结果分析显示,有名管道可以在不同进程之间传递数据,且数据流向明确。...

    从Linux程序中执行shell(程序、脚本)并获得输出结果

    这里,`pipe`创建了管道,`fork`创建子进程,`dup2`将子进程的标准输出重定向到管道的写端,而父进程则从读端读取数据。 3. **使用`popen`函数**: `popen`是C库中的一个函数,它提供了更简洁的方式来执行shell...

    popen使用方法示例

    在C/C++编程中,`popen`是一个非常实用的函数,它允许程序与操作系统命令行进行交互。这个函数在`stdio.h`头文件中定义,可以用来执行一个外部命令并读取或写入其标准输入/输出。下面我们将详细讨论`popen`的使用...

    跨平台实现异步执行命令,类似popen,可同时读写

    popen函数在C和C++中是一个用于执行命令行指令并创建一个与该进程的输入/输出相关的管道的函数。它允许程序读取或写入被执行命令的输出。然而,popen是单向的,即要么只能读,要么只能写,并且不支持异步操作。为了...

    Linux中popen函数的作用小结

    `popen()`是C标准库`stdio.h`的一部分,它通过创建管道(pipe)并在子进程中运行一个shell来实现这一功能。 函数原型如下: ```c #include FILE *popen(const char *command, const char *type); int pclose(FILE ...

    【基础篇】第07篇:PHP代码审计笔记--命令执行漏洞1

    在描述中提到了命令管道符(|)、重定向符(&lt; &gt;&gt;)以及一些可以利用的特殊字符,如Windows中的`|`, `||`, `&`和Linux中的`;`, `|`, `&`。这些字符可以被用来构造复合命令,绕过简单的过滤机制。 为了防止命令执行...

    Linux上实现双向进程间通信管道-zxg623-ChinaUnix博客1

    例如,`popen`和`pclose`函数可以创建一个简单的命令执行管道,但它们仅支持单向流,即要么只能写入,要么只能读出,不能同时进行读写操作。当需要在一个进程中发送数据给另一个进程进行处理,并接收处理结果时,...

Global site tag (gtag.js) - Google Analytics