`

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 C 常用库函数手册

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

    线程和线程编程(linux)

    - **dup2()**:复制文件描述符,并关闭旧的描述符。 - **popen()**:创建一个管道并启动一个子进程。 - **pclose()**:关闭管道并等待子进程结束。 #### 命名管道(FIFO) **命名管道**或FIFO是一种特殊类型的管道...

    进程和线程编程

    - **dup2()**:复制文件描述符,并关闭原来指定位置的描述符。`int dup2(int oldfd, int newfd);` **用途**:通常在管道通信中用于替换标准输入或输出。 **示例代码**: ```c int fd[2]; pipe(fd); /* 在子进程...

    unix下进程与线程编程

    `dup()`和`dup2()`用于复制或替换文件描述符,而`popen()`和`pclose()`则提供了更高级的命令执行和管道功能。管道存在于内核中,因此只有创建管道的进程及其子进程才能访问。 3. 命名管道(FIFO) 命名管道允许不...

Global site tag (gtag.js) - Google Analytics