Liunx — 命名管道

命名管道




管道的一个不足之处就是没有名字,因此,只能用于具有亲缘关系的进程间通信,在命名管道提出后,该限制得到克服. FIFO不 用于管道之处在

于它提供一个路径名与之关联,以FIFO的文件形式存储在文件系统中。命名管道是一个设备文件,因此,及时进 程与创建FIFO的进程不存在亲缘

关系,只要可以访问该路径,就能够通过FIFO相互通信. FIFO按照先进先出原则工作,你先被写 入就先被读出.

那么问题来了,我们如何创建一个命名管道,以及它是怎么使用的呢?

Linux下有两种方式创建命名管道.

一是在Shell下交互地建立一个命名管道
二是在程序使用函数建立命名管道

mknod nameedpipe
创建命名管道的系统函数有两个: mknod和mkfifo. 两个函数均定义在sys/stat.h

#include<sys/types.h>
#include<sys/stat.h>
int mknod(const char* path,mode_t mode,dev_t dev);
int mkfifo(const char* path,mode_t mode);

函数mknod参数中path为创建的命名管道的全路路径: mod为创建的命名管道的模式,指明其存取权限; dev为设备值,该值取决于文件创 建的种

类, 它只是在创建文件时才会用到,这两个函数调用成功都是返回0 失败返回 -1

举个例子: mknod("/tmp/fifo",S_IFIFO|666)

这里的 S_IFIFO|666 指明创建一个命名管道且存取权限为0666,即创建者,与创建者同组的用户,其他用户对该命名管道的访问权限

都是可读可写. 命名管道创建后就可以使用了,命名管道和管道的使用方法基本相同. 只是使用命名管道时,必须先调用open()将其打开.因为命

名管 道是一个存在 于硬盘上的文件,而管道是存在于内存的特殊文件.

需要注意的是,调用open打开命名管道的进程可能会被阻塞.但如果同时用读写方式(O_RDWR)打开,则一定不会阻塞; 如果以只读方式

(O_RDONLY) 打开,则调用open()函数的进程将会被阻塞直到有写方法打开管道; 同样以写方式打开也会阻塞直到有读方式打开管道.

我们可以使用两个函数之一来创建一个命名管道,他们的原型如下:
#include<sys/types.h>
#include<sys/stat.h>
int mkffo(const char* filename,mode_t mode);
int mknod(const char* filename,mode_t mode|S_IFIFO,(dev_t)0);
这两个函数都能创建一个FIFO文件,注意是创建一个真实存在于文件系统中的文件,filename制定了文件名,而mode则指定了文件的读写权限.

这里 意一下mknod函数已经过时了,这里mkfifo是年轻人,所以尽可能用年轻人,让老年人休息休息.

mkfifo函数的作用是创建一个文件,该文件用于提供FIFO功能,既命名管道.上一篇博客所有的管道都是匿名管道。对于文件系统来说,匿名管

道是 不可见的,它的作用权限是在父进程和子进程之间通信.既命名管道是一个可见的额文件,因此,它的作用可以用于任何两个进程 之间,注

意这里的 任意! 但是命名管道还是存在致命缺点->单项通信,这个没办法解决,因为这是管道的性质.

代码举例:



写端代码:

//fifowrite.c

/*************************************************************************
> File Name: fifowrite.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Mon 19 Jun 2017 10:15:40 PM PDT
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#define _PATH_ "./mypipe"
#define _SIZE_ 100

int main()
{
	//首先创建一个_PATH_管道,注意这里的_PATH_是一个宏.
	int ret = mkfifo(_PATH_, 0666 | S_IFIFO);
	if (ret == -1)
	{
		printf("mkfifo error\n");
		return 1;
	}
	int fd = open(_PATH_, O_WRONLY);
	if (fd < 0)
		printf("Open error\n");
	char buf[_SIZE_];
	memset(buf, '\0', sizeof(buf));
	while (1){
		scanf("%s", buf);
		//这里开始往_PATH_管道里面写东西.
		int ret = write(fd, buf, strlen(buf) + 1);
		if (ret < 0)
		{
			printf("write error\n");
			break;
		}
		if (strncmp(buf, "quit", 4) == 0){
			break;
		}
	}
	close(fd);
	return 0;
}


读端代码:

//fiforead.c

/*************************************************************************
> File Name: fiforead.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Mon 19 Jun 2017 09:33:56 PM PDT
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#define _PATH_ "./mypipe"
#define _SIZE_ 100

int main()
{
	//先打开管道.
	int fd = open(_PATH_, O_RDONLY);
	char buf[_SIZE_];
	memset(buf, '\0', sizeof(buf));
	while (1)
	{
		//然后从管道里面拿出数据
		int ret = read(fd, buf, sizeof(buf));
		if (ret <= 0)
		{
			printf("read end or error\n");
			break;
		}
		printf("%s\n", buf);
		if (strncmp(buf, "quit", 4) == 0)
		{
			break;
		}
	}
	close(fd);
	return 0;
}

当这里运行fifowrite.c后,我们就可以看到文件里面里面多形成了一个mypipe.c



然后我们再同时运行读端和写端程序,就可以发生命名管道之间的通信->
注意这里必须要同时运行读端和写端,可以使用Makefile我这里为了直观我没有使用makefile.



命名管道的这些知识大致就这么多,它的应用也大致是这样,他可以实现任意进程之间的通信,但是他还是只有单向通信,所以
我们应该还有更好的通信方式,比如消息队列,信号量,共享内存接下来我会逐一介绍到.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值