管道有两种:无名管道和有名管道。管道是半双工通讯。管道只在内存上开辟空间,不会在磁盘上开辟空间。
半双工通讯指数据可以沿两个方向传送,但同一时刻只能有一个方向的传送
先来说说无名管道吧:
无名管道是由调用pipe函数创建的;函数原型如下:
#include <unistd.h> //头文件
int pipe(int filedes[2]);//函数原型
返回值:成功返回0,出错返回-1
参数filedes返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。
无名管道它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可以应用该管道。
调用fork之后做什么取决于我们想要有的数据流的方向。对于从父进程到子进程的管道,则父进程应关闭管道的读端(fd[0]),
子进程则关闭写端(fd[1]).对于从子进程到父进程的管道,则与之相反。
下面我们用代码来简单实现无名管道:
void main()
{
int fd[2];
pipe(fd);//创建无名管道,并且将fd[0]绑定为读,fd[1]绑定为写
pid_t pid = fork(); //创建子进程
assert(pid != -1);
//这是从子进程到父进程的管道
if(pid == 0)
{
close(fd[0]); //子进程关闭读端
while(1)
{
printf("please input data: ");
fflush(stdout);
char buff[128] = {0};
fgets(buff, 128, stdin); //输入数据到buff中
buff[strlen(buff) - 1] = 0;
if(strcmp(buff, "end") == 0) //以‘end’结束
{
break;
}
write(fd[1], buff, strlen(buff)); //将buff中的数据写入到管道中
}
close(fd[1]); //写完关闭写端
}
else
{
close(fd[1]); //父进程关闭写端
while(1)
{
char buff[128] = {0};
int n = read(fd[0], buff, 127); //从管道读端读取数据,读到buff中
if(n == 0)
{
break;
}
//打开一个文件a.txt,没有的话在当前路径下创建
int fda = open("a.txt", O_WRONLY | O_CREAT | O_APPEND, 0664);
assert(fda != -1);
write(fda, buff, n); //将buff中的数据写到a.txt中
close(fda);//关闭文件
}
close(fd[0]); //读完关闭管道的读端
}
}
接下来我们看看有名管道(FIFO):
FIFO,管道只能由相关进程使用,这些相关进程的共同的祖先进程创建了管道。但是,通过FIFO,不相关的进程也能交换数据。
FIFO是一种文件类型。创建FIFO类似创建文件。
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
返回值,成功则返回0,出错返回-1;
pathname:是创建的文件名字
mode:创建新文件时使用,eg:O_APPEND,O_CREAT (这个和open函数第三个参数一样,具体见open参数)。
如果已经用mkfifo创建了一个FIFO,就可用open打开它。
当打开一个FIFO时,非阻塞标志(O_NONBLOCK)会产生下列影响。
没有指定O_NONBLOCK:open使用时会阻塞运行:如果只有只读打开或者只写打开的时候,open函数会阻塞,直到另一个进程以另一种方式打开此文件。
指定了O_NONBLOCK,则只读的open会立即返回。但是,如果没有进程已经为读而打开一个FIFO,name只写open将会出错返回-1.
read读取数据时:如果没有进程给管道里写数据,read会阻塞,直到有数据或写端关闭。
管道文件如果进行读操作,读了之后文件内存就清空,不存在了。
代码简单实现:
void main()
{
int fd = open("FIFO", O_WRONLY); //A进程以只写的方式打开,open会阻塞,直到另一个进程以另一种方式打开
assert(fd != -1);
printf("fifo file open over\n");
sleep(1);
int n = write(fd, "hello word", strlen("hello word")); //往FIFO里面写了hello word
close(fd);
printf("data write file\n");
}
void main()
{
int fd = open("FIFO", O_RDONLY);//B进程以只读打开
assert(fd != -1);
printf("fifo file open over\n");
char buff[128] = {0};
int n = read(fd, buff, 127); //从FIFO里面读数据,读到buff中
close(fd);
printf("buff = %s\n", buff);
printf("data write file\n");
}
A进程会阻塞在open,等到B进程运行,以另一种方式打开FIFO时,A进程才不阻塞,往下运行,写入数据,B进程从FIFO管道文件中读数据。