打印
[嵌入式linux]

有名管道(FIFO)

[复制链接]
1356|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
shanghaifar|  楼主 | 2013-9-5 11:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sdnumcu 于 2013-9-8 10:46 编辑

本文关键字: linux 管道通信,linux 进程通信方式,有名管道,FIFO
    有名管道的创建可以使用函数mkfifo(),该函数类似于文件中的open()操作,可以指定管道的路径和打开的模式。用户还可以在命令行使用“mknod 管道名 p”来创建有名管道。
    在创建管道成功后,就可以使用open()、read()和write()这些函数了。与普通文件的开发设置一样,对于为读而打开的管道可在open()中设置O_RDONLY,对于为写而打开的管道可在open()中设置O_WRONLY,在这里与普通文件不同的是阻塞问题。由于普通文件在读写时不会出现阻塞问题,而在管道的读写中却有阻塞的可能,这里的非阻塞标志可以在open()函数中设定为O_NONBLOCK。下面分别对阻塞打开和非阻塞打开的读写进行讨论。
    对于读进程:
    ● 若该管道是阻塞打开,且当前FIFO内没有数据,则对读进程而言将一直阻塞到有数据写入。
    ● 若该管道是非阻塞打开,则不论FIFO内是否有数据,读进程都会立即执行读操作。即如果FIFO内没有数据,则读函数将立刻返回0。
    对于写进程:
    ● 若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。
    ● 若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。
    表1列出了mkfifo()函数的语法要点。
表1 mkfifo()函数语法要点
所需头文件
#include <sys/types.h> #include <sys/state.h>
函数原型
int mkfifo(const char *filename,mode_t mode)
函数传入值
filename:要创建的管道
mode
O_RDONLY:读管道
O_WRONLY:写管道
O_RDWR:读写管道
O_NONBLOCK:非阻塞
O_CREAT:如果该文件不存在,那么就创建一个新的文件,并用第3个参数为其设置权限
O_EXCL:如果使用O_CREAT时文件存在,那么可返回错误消息。这个参数可测试文件是否存在
函数返回值
成功:0
出错:-1
    表2再对FIFO相关的出错信息进行归纳,以方便用户查错。
表2 FIFO相关的出错信息
EACCESS
参数filename所指定的目录路径无可执行的权限
EEXIST
参数filename所指定的文件已存在
ENAMETOOLONG
参数filename的路径名称太长
ENOENT
参数filename包含的目录不存在
ENOSPC
文件系统的剩余空间不足
ENOTDIR
参数filename路径中的目录存在但却非真正的目录
EROFS
参数filename指定的文件存在于只读文件系统内
    下面的实例包含两个程序,一个用于读管道,另一个用于写管道。其中在读管道的程序中创建管道,并且作为main()函数里的参数由用户输入要写入的内容;读管道的程序会读出用户写入到管道的内容。这两个程序采用的是阻塞式读写管道模式。
    写管道的程序如下:
    /* fifo_write.c */
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    #define MYFIFO "/tmp/myfifo" /* 有名管道文件名 */
    #define MAX_BUFFER_SIZE PIPE_BUF /* 定义在limits.h中 */

    int main(int argc, char * argv[]) /* 参数为即将写入的字符串 */
    {
        int fd;
        char buff[MAX_BUFFER_SIZE];
        int nwrite;

        if(argc <= 1)
        {
            printf("Usage: ./fifo_write string\n");
            exit(1);
        }
        sscanf(argv[1], "%s", buff);

        /* 以只写阻塞方式打开FIFO管道 */
        fd = open(MYFIFO, O_WRONLY);
        if (fd == -1)
        {
            printf("Open fifo file error\n");
            exit(1);
        }

        /* 向管道中写入字符串 */
        if ((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0)
        {
            printf("Write '%s' to FIFO\n", buff);
        }
        close(fd);
        exit(0);
    }
    读管道程序如下:
    /* fifo_read.c */
    (头文件和宏定义同fifo_write.c)
    int main()
    {
        char buff[MAX_BUFFER_SIZE];
        int fd;
        int nread;

        /* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建 */
        if (access(MYFIFO, F_OK) == -1)
        {
            if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST))
                {
                    printf("Cannot create fifo file\n");
                    exit(1);
                }
            }
            /* 以只读阻塞方式打开有名管道 */
            fd = open(MYFIFO, O_RDONLY);
            if (fd == -1)
            {
                printf("Open fifo file error\n");
                exit(1);
            }

            while (1)
            {
                memset(buff, 0, sizeof(buff));
                if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0)
            {
                printf("Read '%s' from FIFO\n", buff);
            }
        }
        close(fd);
        exit(0);
    }
    为了能够较好地观察运行结果,需要把这两个程序分别在两个终端里运行,在这里首先启动读管道程序。读管道进程在建立管道后就开始循环地从管道里读出内容,如果没有数据可读,则一直阻塞到写管道进程向管道写入数据。在启动了写管道程序后,读进程能够从管道里读出用户的输入内容,程序运行结果如下。
    终端一:
    $ ./fifo_read
    Read 'FIFO' from FIFO
    Read 'Test' from FIFO
    Read 'Program' from FIFO
    …
    终端二:
    $ ./fifo_write FIFO
    Write 'FIFO' to FIFO
    $ ./fifo_write Test
    Write 'Test' to FIFO
    $ ./fifo_write Program
    Write 'Program' to FIFO
    …

相关帖子

沙发
shanghaifar|  楼主 | 2013-9-5 14:05 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

47

主题

81

帖子

0

粉丝