linux命名管道fifo通信示例

目录

概述

要点

1 虽然fifo是一个文件,但是两个进程使用fifo时,各自都要用open函数打开fifo。

2 open有读写等多种模式。此外模式之间还可以组合。

读(O_RDONLY),不论是否阻塞

写+阻塞(O_WRONLY)

写+非阻塞(O_WRONLY | O_NONBLOCK)

3 程序启动次序

4 程序退出

代码

主进程:

子进程:


概述

管道适用于进程间通信。按照陈硕所著的《Linux多线程服务端编程:使用muduo C++网络库》3.4节的说法,“进程间最好使用TCP”。但是在实际工作中,由于各种原因,我还是喜欢使用管道或者其他方式完成进程间通信。

这里给出一个命名管道的通信示例。命名管道fifo是一个文件,在程序master(主进程)中创立,其名字由mkfifo函数定下来。主进程负责写入数据到管道。程序slave(子进程)负责读取数据,并显示。退出时,用户要在主进程中键入quit指令。两个进程各自使用close函数结束对fifo的访问。并且由读进程调用unlink函数删除fifo文件。

两个程序各自占据一个console。

要点

1 虽然fifo是一个文件,但是两个进程使用fifo时,各自都要用open函数打开fifo。

2 open有读写等多种模式。此外模式之间还可以组合。

读(O_RDONLY),不论是否阻塞

open处于读模式下,尝试打开一个不存在的fifo将导致open直接返回-1,打开失败。

写+阻塞(O_WRONLY)

open处于写模式+阻塞下,假如子进程还没有用读模式的open来打开fifo,则写模式的open将阻塞,直到fifo被子进程读模式的open打开。 

写+非阻塞(O_WRONLY | O_NONBLOCK)

open处于写模式+非阻塞下,假如子进程还没有用读模式的open来打开fifo,则写模式的open将直接返回-1,打开失败。

3 程序启动次序

在fifo没有创建时就让slave文件(子进程)open管道,尝试打开一个不存在的fifo将导致open直接返回-1,打开失败。下面的截图展示了这个情况:

所以应该先启动主进程来创建mkfifo。

open处于写模式+阻塞下试图打开fifo,假如子进程还没有用读模式的open来打开fifo,则写模式的open将阻塞,直到fifo被子进程读模式的open打开。下图展示了主进程(右)的阻塞。

只有在主进程先启动,随后启动子进程的情况下,两个进程的open才会先后成功打开fifo:

 

4 程序退出

 两个进程都要在退出前调用close函数关闭fifo文件。此外,读进程在close之后还要调用unlink删除fifo文件。

代码

主进程:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
#include <stdio.h>

const char * pFifoName = "fifoM";

int main(void)
{
	if(access(pFifoName, F_OK) == -1)
	{
		//检查fifo文件是否存在,不存在就创建一个
		mkfifo(pFifoName, 0644);
	}

	int p = open(pFifoName, O_WRONLY);
	if(p != -1)
	{
		//假如读管道的进程还没就打开写模式的管道文件,则open将阻塞直到读进程启动
		std::cout<<"open"<<std::endl;
		char readin[128];
		while(true)
		{
			std::cin.getline(readin, 127);
			readin[127]=0;
			//printf("%d %d cease\n", readin[4], readin[6]);
			if(strcmp("quit", readin) == 0) 
			{				
				break;
			}
			write(p, readin, strlen(readin));
		}

		close(p);
	}
	return 0;
}

子进程:

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

const char * pFifoName = "fifoM";

int main(void)
{
	int p = open(pFifoName, O_RDONLY | O_NONBLOCK);

	if(p != -1)
	{
		char recv[128];
		while(true)
		{
			int iRet = read(p, recv, 127);
			if(-1 == iRet)
			{
				if(errno == EAGAIN)
				{
					//std::cout<<"again"<<std::endl;
					//非阻塞模式下,假如read读不到数据(fifo没有数据),则进入这个分支
				}
				else
				{
					break;
				}
			}
			else if(iRet > 0)
			{
				recv[iRet] = 0;
				std::cout<<recv<<std::endl;
			}
			else if(0 == iRet)
			{
				//假如写进程退出了,则iRet返回0
				//std::cout<<"0read"<<std::endl;
				break;
			}
			else
			{
				break;
			}
		}
		
		close(p);
		std::cout<<"break;"<<std::endl;
		
    	unlink(pFifoName); //删除文件
	}
	else
	{
		std::cout<<"fail to open"<<std::endl;
	}
	return 0;
}
				

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值