嵌入式Linux管道使用实例,7.2.2 有名管道(FIFO)--嵌入式linux应用开发--嵌入式linux中文站...

7.2.2有名管道(FIFO)

管道的一个很重要的问题是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named

pipe或FIFO)提出后,这个问题就得到解决。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。

1、命令行下的有名管道

先来看一下在命令行下如何使用FIFO,主要使用命令mkfifo

#mkfifo /tmp/fifo

此命令在/tmp目录下面建立一个称为fifo的命名管道

使用命令ls –l

/tmp/fifo,可以得到与下面类似的结果:

prw-r--r--  1 root root 0  3月 25 12:10 /tmp/fifo

然后输入命令

#cat /tmp/fifo

此命令用于输出FIFO的内容,这时这个终端就会挂起,等待FIFO的输出。

此时,打开另一个终端,例如ALT+F3用于打开3号终端。

在此输入

#echo This is fifo > /tmp/fifo

就可以发现刚才输入cat的命令有了输出。

#cat /tmp/fifo

This is fifo

可以明显的看出刚才的cat命令和echo命令不是父子进程,却能共享数据,这就是FIFO的应用实例。

2、编程中使用命令管道

在文件系统中创建一个命名管道(FIFO)使用函数mkfifo()

#include

#include

int mkfifo(const char * pathname, mode_t mode);

参数一 pathname指定了FIFO在文件系统中的路径;

参数二mode指定了FIFO的读写权限,与打开普通文件的open()函数中的mode 参数相同。mkfifo函数如果调用成功的话,返回值为0;如果调用失败返回值为-1。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回-1,并且将系统错误代码errno设置成EEXIST,所以一般典型的代码会检查是否存在FIFO,如果通过errno判断存在此FIFO,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如read、write、close等等。

注意点:如果当前打开操作是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置了阻塞标志);或者,成功返回(当前打开操作没有设置阻塞标志)。设置阻塞标记是在open函数的mode参数是否O_NONBLOCK(例如非阻塞读模式的话可以将mode设置成O_WRONLY|O_NONBLOCK)。

如果当前打开操作是为写而打开FIFO时,如果已经有相应进程为读而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作设置了阻塞标志);或者,返回ENXIO错误(当前打开操作没有设置阻塞标志)。

下面我们就利用此函数来实现刚才shell里mkfifo命令所演示的功能:

程序一、创建FIFO

/* mymkfifo.c */

#include

#include

#include

#include

#include

#define FIFO_FILE "/tmp/progfifo"

int main()

{

int ret;

ret = mkfifo(FIFO_FILE, O_CREAT | O_EXCL);

if (ret == 0) {

printf("Create FIFO

success:%s\n", FIFO_FILE);

} else if (errno == EEXIST) {

/*mkfifo函数返回-1且errno被设置成EEXIST,说明要创建的FIFO已存在*/

printf("Warning: FIFO %s already

exists.\n", FIFO_FILE);

} else {

printf("Create FIFO

fail:%s.\n", FIFO_FILE);

}

return 0;

}

使用命令gcc –o mymkfifo  mymkfifo.c 编译程序

运行命令./mymkfifo ,可得到结果:

Create FIFO success:/tmp/progfifo.

这时使用命令  ls

–l  /tmp/progfifo  ,应该可以得到与下面相似的结果:

prw-r--r--  1 root root 0  3月 25 17:40 /tmp/progfifo

说明我们创建FIFO已经成功了。

若再次运行命令

./mymkfifo,得到如下结果:

Warning: FIFO /tmp/progfifo already exists.

说明通过mkfifo函数的返回值和errno的值,我们判断出FIFO已存在的错误。

程序二、写数据到FIFO 中

/*wfifo.c */

#include

#include

#include

#include

#include

#define FIFO_FILE "/tmp/progfifo"

int main()

{

int fd;

char data[] = "Data in FIFO.";  /* 将要写入FIFO的数据 */

fd = open(FIFO_FILE, O_WRONLY);  /* 就像一般的文件一样打开FIFO文件

* 但注意这里以阻塞方式打开FIFO文件,若要非阻塞用O_WRONLY|O_NONBLOCK*/

*/

if (fd < 0) {

printf("Open FIFO fail:%s.\n",

FIFO_FILE);

exit(1);

}

write(fd, data, sizeof(data));   /* 向FIFO文件中写数据,此时程序会挂起,直到FIFO中的数据被读出 */

printf("Here, the data has been read

out.\n"); /* 如果运行到这行,说明写入的数据已经被全部取出,写进程继续运行了

*/

return (0);

}

因为读写关联较大,所以我们先不急着运行wfifo,先来看如何从FIFO数据中读数据。

程序三、从FIFO中读数据

/* rfifo.c */

#include

#include

#include

#include

#include

#include

#define FIFO_FILE "/tmp/progfifo"

int main()

{

int fd;

char data[20] = "";

/* 以阻塞方式打开FIFO文件,若要非阻塞用O_RDONLY|O_NONBLOCK*/

fd = open(FIFO_FILE, O_RDONLY);

if (fd < 0) {

printf("Open FIFO fail:%s.\n",

FIFO_FILE);

exit(1);

}

read(fd, data, sizeof(data));  /* 这里从FIFO中读数据,注意如果此时FIFO中没有数据,程序也会挂起等待数据 */

printf("FIFO data read: %s\n", data);

return (0);

}

现在我们将读写两程序联合起来运行看结果(请务必先运行mymkfifo建立FIFO文件)。

编译wfifo.c和rfifo.c。

在一个终端里运行程序./wfifo,发现程序挂起,说明在等待FIFO中数据被取出。

这时在另一个终端里运行程序./rfifo,可以看到运行结果

#./rfifo

FIFO data read: Data in the FIFO.

然后再回去刚才执行wfifo的终端里发现程序不再阻塞,已经继续执行了。并且显示了如下信息:

Here, the data has been read out.

如果两个程序换个顺序执行,就是先执行rfifo,再运行wfifo,也可以发现rfifo事先挂起,直到wfifo写入数据后再继续运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值