pipe/popen/fifo
pipe(管道)
- 专用于父子进程通信, 函数原型 int pipe(int fd[2])
- fd[0]表示输入, fd[1]表示输出
- 如果父子进程要双向通信, 可以通过类似信号的功能进行控制, 也可以简单地打开两个pipe
以下例子, 打开两个pipe, 第一个pipe用于父进程向子进程发送信息, 第二个pipe用于子进程向父进程发送消息
子进程接收到消息后, 将消息转成大写然后发送给父进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
char *strupr(char *str){
char *orign=str;
for(;*str != 0;++str)
*str=toupper(*str);
return orign;
}
void err_quit(const char *str){
perror(str);
exit(1);
}
int main(){
int n;
int fd1[2], fd2[2];
pid_t pid;
char line[1024];
if(pipe(fd1)<0 || pipe(fd2)<0)
err_quit("pipe error");
if((pid =fork())<0){
err_quit("pipe error");
}else if(pid >0 ){
close(fd1[0]);
close(fd2[1]);
write(fd1[1],"hello world\n",12);
n=read(fd2[0],line,1024);
write(STDOUT_FILENO,line,n);
}else{
close(fd1[1]);
close(fd2[0]);
n=read(fd1[0],line,1024);
write(STDOUT_FILENO,line,n);
line[n]='\0';
write(fd2[1],strupr(line),n);
}
exit(0);
}
popen和pclose
- 函数原型FILE *popen(const char *cmdstring, const char *type) , type的参数为"r"或"w"
- 用于父子进程通信, popen会自动fork子进程、创建pipe和关闭不需要的pipe端
- popen的实现有可理解为execl("/bin/sh","sh","-c",cmdstring,NULL)
- 当父进程向子进程发送信息时(type="w"), 实际就是向shell发送命令;
当父进程从子进程获取信息时(type="r"), 实际就是读取shell的执行结果 - 虽然popen的返回是FILE,但关闭是要用pclose(fp)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define MAXLINE 1024
void err_quit(const char *str){
perror(str);
exit(1);
}
int main(){
char line[MAXLINE];
FILE *fpin;
if((fpin=popen("ls -l","r")) == NULL)
err_quit("popen error");
while(fgets(line,MAXLINE,fpin) != NULL){
if(fputs(line,stdout) ==EOF)
err_quit("fputs error");
}
if(ferror(fpin))
err_quit("fpin error");
if(pclose(fpin)==-1)
err_quit("pclose error");
return 0;
}
fifo
- int mkfifo(const char *pathname,mode_t mode), 创建一个通信文件, 参数同open
- mkfifo后, 以open打开文件, 打开方式为只读或只写, 另外可以非阻塞方式打开
- 以只读打开时, 函数会阻塞直到有进程以只写方式打开
- 以只写打开时, 函数会阻塞直到有进程以只读方式打开
- 可用于非父子进程通信, 双向通信时开需两个
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FILE_MODE S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IROTH
void err_quit(const char *str){
perror(str);
exit(1);
}
int main(){
char *pathname="./fifobuf";
pid_t pid;
if(mkfifo(pathname,FILE_MODE)<0)
err_quit("mkfifo error");
if((pid=fork())<0){
err_quit("fork error");
}else if(pid >0){
int fd;
if((fd=open(pathname,O_RDONLY))<0)
err_quit("open error");
char buf[100];
int n;
if((n=read(fd,buf,100)) < 0)
err_quit("read error");
buf[n]=0;
puts(buf);
exit(0);
}else{
int fd;
if((fd=open(pathname,O_WRONLY))<0)
err_quit("open error");
char *str="hello world";
write(fd,str,strlen(str));
exit(0);
}