linux 之有名管道 (atom)

博客介绍了无名管道只能在亲缘关系进程间传输数据的缺点,重点讲解了有名管道可在任意进程间传输。详细介绍了mkfifo()函数,包括其头文件、原型、返回值、特点及使用步骤,还给出测试程序和结果,强调写操作的原子性等重点。

文章目录

无名管道的缺点:只能在父子进程或者其它具有亲缘关系的进程间进行数据传输。
有名管道:可以在任意进程之间传输。

mkfifo() 函数

头文件

#include<sys/types.h>
#include<sys/stat.h>

函数原型

filename就是有名管道的名字,mode表示rwx权限
int mkfifo(const char *filename,mode_t mode);

返回值
成功:0
失败:-1

特点:

  • 有文件名,可以使用open() 函数打开

  • 可以实现任意进程间的数据传输

  • write() 和 read() 可能会阻塞进程:空读 or 满写

  • write()操作具有原子性。无名管道缓存只要由任意的空闲空间,那么write就可以往里面写;而有名管道在write之前会检查有名管道的空闲空间,确认空闲空间充足的情况下,才会去执行写操作,否则不会写。

使用步骤

  • 在第一个进程里面利用 mkfifo() 创建有名管道。
  • open() 打开有名管道,write() / read() 数据。
  • close() 有名管道。
  • 第二个进程open() 有名管道,read() / write() 数据。
  • close() 有名管道。

测试程序

注意不要自己手动创建管道文件!!!运行会发生异常!!!
让 fifo_read 进程 自己创建才能正常工作!!!

fifo_read.c

#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#include<unistd.h>
#include<string.h>

//有名管道文件名

#define 		MYFIFO		"./myfifo"
//4096,定义在 limits.h 中
#define		MAX_BUFFER_SIZE	PIPE_BUF

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

	//判断有名管道是否存在,若不存在,则以相应的权限创建
	if(-1 == access(MYFIFO,F_OK))
	{
		if((mkfifo(MYFIFO,0666) < 0) && (errno != EEXIST))
		{
			printf("Can not create fifo file.\n");
			exit(0);
		}
	}
	//以只读方式打开有名管道
	fd = open(MYFIFO,O_RDONLY);
	if(-1 == fd)
	{
		printf("Open fifo file error.\n");
		exit(1);
	}
	//循环读取有名管道数据
	while(1)
	{
		memset(buf,0,sizeof(buf));
		if((nread = read(fd,buf,MAX_BUFFER_SIZE)) > 0)
		{
			/* 每一次都为 4096, 内存的页大小,
			 * 管道规则:
			 * 1、满写阻塞,空读阻塞
			 * 2、没写满不能读,没读空不能写
			 * 3、半双工通信,读写教程互斥访问管道
			 * 4、通信数据是字节流形式
			 * 5、读完后管道中的数据丢弃
			 */
			printf("nread = %d\n", nread);
			printf("Read '%s' from fifo.\n",buf);
		}
	}
	close(fd);
	exit(0);
}

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>
#include<unistd.h>
#include<string.h>

//有名管道文件名

#define		MYFIFO		"./myfifo"
//4096,定义在 limits.h 中
#define  MAX_BUFFER_SIZE PIPE_BUF

int main(int argc,char **argv)
{
	int fd;
	char buf[MAX_BUFFER_SIZE];
	int nwrite;
	
	if(argc <= 1)
	{
		printf("Usage: ./fifo_write string.\n");
		exit(1);
	}
	//填充命令行第一个参数到buf
	sscanf(argv[1],"%s",buf);
	//以只写阻塞方式打开fifo管道
	fd = open(MYFIFO,O_WRONLY);

	if(-1 == fd)
	{
		printf("Open fifo file error.\n");
		exit(1);
	}
	//向管道中写入字符串
	if((nwrite = write(fd,buf,MAX_BUFFER_SIZE)) > 0)
	{
		/* 每次都是 4096 */
		printf("nwrite = %d\n", nwrite );
		printf("Write '%s' to fifo.\n",buf);
	}
	close(fd);
	exit(0);
}

测试结果

  • 编译
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ ls
fifo_read.c  fifo_write.c
jl@jl-virtual-machine:~/test/11_1$ gcc fifo_read.c -o fifo_read
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ gcc fifo_write.c -o fifo_write
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ ls
fifo_read  fifo_read.c  fifo_write  fifo_write.c
jl@jl-virtual-machine:~/test/11_1$ 

  • 打开一个终端,在这个终端1中,先运行fifo_read,由于管道是空的,可以看到进程被read() 阻塞了,shell无终端控制权
jl@jl-virtual-machine:~/test/11_1$ ./fifo_read 


  • 打开另一个终端,就叫它终端2,运行fifo_write,向管道里面写入数据
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ ./fifo_write 666
Write '666' to fifo.
jl@jl-virtual-machine:~/test/11_1$ ./fifo_write 777
Write '777' to fifo.
jl@jl-virtual-machine:~/test/11_1$ 

此时终端1中:

jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ 
jl@jl-virtual-machine:~/test/11_1$ ./fifo_read 
Read '666' from fifo.
Read '777' from fifo.


重点

任意进程之间数据传输。
写是原子操作类型。
设置写的size是4096,每次写都会阻塞在write,直到接收进程 read 4096。
而且同时运行两个接收方进程,写一次只能有一个进程接收到发送方内容。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值