匿名管道(pipe)和命名管道(mkfifo)
进程间通信必须通过内核提供的通道。
匿名管道通过打开的文件描述符来标识的。——用于具有亲缘关系间进程之间的通信。
int pipe(int fds[2]);//返回值0表示成功,-1表示失败
fd[0]:读 fd[1]:写
写数据时要关闭读端
读数据时要关闭写端
命名管道借助于文件系统实现,文件系统中的路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道。——用于具有非亲缘关系间进程之间的通信。
命名管道的打开规则:
如果当前打开操作是为读而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
O_NONBLOCK enable:立刻返回成功
如果当前打开操作是为写而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
O_NONBLOCK enable:立刻返回失败,错误码为ENXIO
需要注意的是打开的文件描述符默认是阻塞的.
管道的创建
管道文件大小为0,没有亲缘关系的文件也能通过管道名,来取到该管道中的缓存。
//创建管道文件 int mkfifo(const char *name,mode_t mode)
//打开管道文件
int fd=open(name,O_RDONLY);读
int fd=open(name,O_WRONLY);写
匿名管道是由pipe函数创建 并打开的
命名管道是由mkfifo函数创建 的 ,打开用open
命名管道和匿名管道唯一的区别就是在创建的打开,一旦这些工作完成后,它们有相同的意义。
/*
* 父进程通过命令行的方式输入内容(argv[1])写入管道
* 子进程从管道中读取数据并输出到标准输出
*
* note: ./pipe hello world
* 仅能输出hello(argv[1]),word(argv[2])不能输出.
*/
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int pipefd[2];
pid_t pid;
char recv_buf[1024];
int len;
if(argc < 2)
{
perror("Usage error:");
exit(1);
}
if(pipe(pipefd) < 0)
{
perror("pipe()");
exit(1);
}
pid = fork();
if(-1 == pid)
{
perror("fork()");
exit(1);
}
if(0 == pid)
{
close(pipefd[1]);
while((len = read(pipefd[0],recv_buf,10)) > 0 )
write(1,recv_buf,len);
puts("\n");
close(pipefd[0]);
exit(0);
}
else
{
close(pipefd[0]);
write(pipefd[1],argv[1],strlen(argv[1]));
close(pipefd[1]);
wait(NULL);
exit(0);
}
exit(0);
}
/*
* 父进程通过命令行的方式输入文件路径名(argv[1])写入管道
* 子进程从管道中读取数据并输出到标准输出
*
* eg. ./pipe pipe.c
* ./pipe ./pipe.c
* ./pipe ./home/user/IPC/pipe.c
*/
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int pipefd[2];
pid_t pid;
char recv_buf[1024];
char send_buf[1024];
int recv_len;
size_t send_len;
FILE *fp = NULL;
if(argc < 2)
{
perror("Usage error:");
exit(1);
}
if(pipe(pipefd) < 0)
{
perror("pipe()");
exit(1);
}
pid = fork();
if(-1 == pid)
{
perror("fork()");
exit(1);
}
if(0 == pid)
{
close(pipefd[1]);
while((recv_len = read(pipefd[0],recv_buf,10)) > 0 )
write(1,recv_buf,recv_len);
puts("\n");
close(pipefd[0]);
exit(0);
}
else
{
close(pipefd[0]);
fp = fopen(argv[1],"r");
if(NULL == fp)
{
perror("fopen()");
exit(1);
}
while((send_len = fread(send_buf,1,10,fp)) > 0)
write(pipefd[1],send_buf,send_len);
fclose(fp);
close(pipefd[1]);
wait(NULL);
exit(0);
}
exit(0);
}
公共头文件public.h:
#ifndef PUBLIC_H__
#define PUBLIC_H__
#define MKFIFO_NAME "tp" //定义管道文件名
#endif
写端代码(write.c):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "public.h"
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char *argv[])
{
mkfifo(MKFIFO_NAME, 0644);
int infd = open("Makefile", O_RDONLY);
if (infd == -1)
ERR_EXIT("open error");
int outfd;
outfd = open(MKFIFO_NAME, O_WRONLY);
if (outfd == -1)
ERR_EXIT("open error");
char buf[1024];
int n;
while ((n = read(infd, buf, 1024)) > 0)
write(outfd, buf, n);
close(infd);
close(outfd);
return 0;
}
读端代码(read.c):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "public.h"
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char *argv[])
{
int outfd = open("Makefile2", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (outfd == -1)
ERR_EXIT("open error");
int infd;
infd = open(MKFIFO_NAME, O_RDONLY);
if (infd == -1)
ERR_EXIT("open error");
char buf[1024];
int n;
while ((n = read(infd, buf, 1024)) > 0)
write(outfd, buf, n);
close(infd);
close(outfd);
unlink(MKFIFO_NAME); // delete a name and possibly the file it refers to
return 0;
}
PS:部分内容来源于其他博客,侵权删。