一、有名管道的简单说明
无名管道只能在具有亲缘关系的进程间通信,大大地限制了管道的使用。而有名管道的出现则突破了这种限制,它可以使任意两个进程间进行通信。该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作,使用非常方便。。不过值得注意的是,FIFO 是严格地遵循先进先出规则的,对管道及FIFO 的读总是从开始处返回数据,对它们的写则把数据添加到末尾,它们不支持如lseek()等文件定位操作。
有名管道的创建可以使用函数mkfifo(),该函数类似文件中的open()操作,可以指定管道的路径和打开的模式。在创建管道成功之后,就可以使用open()、read()和write()这些函数了。与普通文件的开发设置一样,对于为读而打开的管道可在open()中设置O_RDONLY,对于为写而打开的管道可在open()中设置O_WRONLY,在这里与普通文件不同的是阻塞问题。由于普通文件的读写时不会出现阻塞问题,而在管道的读写中却有阻塞的可能,这里的非阻塞标志可以在open()函数中设定为O_NONBLOCK。下面分别对阻塞打开和非阻塞打开的读写进行讨论。
(1)对于读进程
- 若该管道是阻塞打开,且当前FIFO 内没有数据,则对读进程而言将一直阻塞到有数据写入。
- 若该管道是非阻塞打开,则不论FIFO 内是否有数据,读进程都会立即执行读操作。即如果FIFO内没有数据,则读函数将立刻返回0。
- 若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。
- 若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。
二、有名管道的创建函数
管道创建函数如下所示:
int mkfifo(const char *filename,mode_t mode)
filename:要创建的管道
mode : O_RDONLY,读管道
O_WRONLY,写管道
O_RDWR,读写管道
O_NONBLOCK:非阻塞
O_CREAT:如果该文件不存在,那么就创建一个新的文件,并用第三个参数为其设置权限
O_EXCL:如果使用O_CREAT 时文件存在,那么可返回错误消息。这一参数可测试文件是否存在
返回值:0成功,其他返回错误代码
操作中经常会出现以下错误如下表所示(方便出错查询):
三、测试
编写一个实例进行测试:需要编写两个独立进程,一个进程用来读取传入的数据,一个进程用来写入数据;在读进程当中首先创建的fifo文件,然后打开并不停的读取FIFO文件当中的内容,在写进程当中打开FIFO文件然后向FIFO文件当中写入相应的内容。具体如下:
读端:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FIFO_NAME "yl_fifo" // 定义FIFO文件的名称
#define BUFFER_SIZE 256 // 定义缓冲区的大小
/* 创建FIFO文件,并以阻塞方式读取FIFO文件当中的内容
*
*/
int main(void)
{
int ret;
int fd;
char buf[BUFFER_SIZE];
int buflen;
/* 创建FIFO文件 */
if(-1 == access(FIFO_NAME, F_OK)) // 判断FIFO文件是否存在
{
ret = mkfifo(FIFO_NAME, 0666); // 以可读可写方式创建一个FIFO文件
if(-1 == ret)
{
printf("mkfifo error!\n");
return -1;
}
}
fd = open(FIFO_NAME, O_RDONLY); // 打开这个文件
if(-1 == fd)
{
printf("open error!\n");
return -1;
}
/* 以阻塞的方式读取文件当中的内容 */
while(1)
{
memset(buf, 0, BUFFER_SIZE);
buflen = read(fd, buf, BUFFER_SIZE);
if(buflen > 0)
{
buf[buflen] = '\0';
if(!strcmp("quit", buf)) // 如果读到的信息是quit,则退出
{
return 0;
}
else // 将读取的信息打印出来
{
printf("Read from fifo : %s\n", buf);
}
}
}
close(fd); // 关闭这个文件
return 0;
}
写端:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FIFO_NAME "yl_fifo" // 定义FIFO文件的名称
#define BUFFER_SIZE 256 // 定义缓冲区的大小
/* 向FIFO文件当中写入信息
* usage : fifo_write <info>
*/
int main(int argc, char *argv[])
{
int fd;
char buf[BUFFER_SIZE];
int buflen;
if(2 != argc)
{
printf("usage : %s <info>\n", argv[0]);
return -1;
}
fd = open(FIFO_NAME, O_WRONLY); // 打开这个文件
if(-1 == fd)
{
printf("open error!\n");
return -1;
}
/* 将消息写入FIFO文件当中 */
sprintf(buf, "%s", argv[1]);
buflen = write(fd, buf, BUFFER_SIZE);
if(buflen <= 0)
{
printf("write error!\n");
return -1;
}
else
{
printf("Write to fifo : %s\n", buf);
}
close(fd); // 关闭这个文件
return 0;
}
对读端和写端分别进行编译和运行如下所示: