linux 之有名管道 (atom)

文章目录

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

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。
而且同时运行两个接收方进程,写一次只能有一个进程接收到发送方内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值