您的位置:首页 > 编程语言

服务器编程之--用命名管道(FIFO)来做进程间通信

2015-01-20 15:40 465 查看
最近在研究进程间通信,要实现两个非亲缘关系的进程间进行通信,用匿名管道不行,只能用命名管道。

有名管道简介

也称FIFO,系统提供一个路径名与此管道关联,以FIFO形式存在与文件系统中。

生存周期从被创建开始,到该管道文件被删除(进程结束不会造成管道消失)。

数据在管道之间以无格式流式传递。

只需要建立一个有名管道便可进行读写操作。遵从FIFO原则,不保证操作的原子性。

优点是使用方便简单,可以作为任何进程间通信手段,缺点是功能上有很多限制。

命名管道FIFO网上一搜一大堆,在这里我主要分享一下,如果做到进程间流畅地通信,实用为主

1. 首先创建管道

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include <iostream>
#define FIFO_READ "/gyl/fiforead"
#define FIFO_WRITE "/gyl/fifowrite"
using namespace std;
#define MASIZE 1024
int main()
{
    int rfd,wfd;
    char buf[1024];
	// 删除之前存在的管道
	system("./delpipe.sh");

	cout <<"create pipe fifo write ============>" <<endl;
    umask(0);
	// 创建写管道
    if(mkfifo(FIFO_WRITE,S_IFIFO|0666) < 0)
	{
		perror("mkfifo");
		exit(1);
    }
	cout <<"create pipe fifo write success --------->" <<endl;
	// 创建读管道
	cout <<"create pipe fifo read ===============>" <<endl;
	if (mkfifo(FIFO_READ, S_IFIFO|0666) < 0) 
	{
		perror("mkfifo");
		exit(1);
	}
	cout <<"create pipe fifo read success ------------->" <<endl;
    umask(0);
	return 0;
}


创建成功之后 你会发现在/gyl 目录下有fiforead ,fifowrite 两个管道文件



另外每次创建管道时,应将原来的管道删除掉
system("./delpipe.sh");  这段代码就是这个作用


delpipe.sh

#!/bin/bash
rm /gyl/fifowrite
rm /gyl/fiforead


2. 之后了创建一个服务端server,一个客户端client

客户端先读,服务端写,之后客户再写,服务端读,就是这样一个交互过程

服务端代码 server.cpp

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include <iostream>
#include "memop.h"
#define FIFO_READ "/gyl/fiforead"
#define FIFO_WRITE "/gyl/fifowrite"
using namespace std;
#define MASIZE 1024

int main()
{
    int rfd,wfd;
    char buf[1024];
	
	cout <<"open write pipe : fifowrite =============>" <<endl;
    wfd=open(FIFO_WRITE,O_WRONLY);
    if(wfd==-1)
	{
		cout <<"open error for write " <<endl;
        perror("open");
        exit(0);
    }
	cout <<"wfd = " <<wfd <<endl;

	cout <<"open read pipe : fiforead ===============>" <<endl;
    while((rfd=open(FIFO_READ,O_RDONLY))==-1)
	{
	     cout <<"start to open ==============>" <<endl;
         sleep(1);
    }
	cout <<"rfd = " <<rfd <<endl;

    while(1)
	{
		memset(buf, 0, sizeof(buf));
        printf("server: ");
		CMemOp kMemOp;
		kMemOp.InitWrite();
		kMemOp.WriteInt(1008);
		kMemOp.WriteInt(234);
		kMemOp.GetBuffer(buf, sizeof(buf));
        //scanf("%s",buf);
        int wNum = write(wfd,buf,kMemOp.GetBufferSize());
		cout << "wNum = " <<wNum <<endl;

		memset(buf, 0, sizeof(buf));
        printf("client:");
        if(read(rfd,buf,1024)<0)
		{
            perror("read");
            exit(1);
        }
        printf("%s\n",buf);
        if(strcmp(buf,"exit")==0)
		{
            exit(0);
        }
		
    }
}


客户端代码 client.cpp

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include <iostream>
#include "memop.h"
using namespace std;
#define FIFO_READ "/gyl/fifowrite"
#define FIFO_WRITE "/gyl/fiforead"
#define MASIZE 1024

int main()
{
    int rfd,wfd;
    char buf[1024];
    umask(0);
	cout <<"open read pipe:  fifowrite =========>" <<endl;
    while((rfd=open(FIFO_READ,O_RDONLY))==-1){
     sleep(1);
    }
	cout <<"rfd = " <<rfd <<endl;

	cout <<"open write pipe: fiforead ===========>" <<endl;
    wfd=open(FIFO_WRITE,O_WRONLY);
    if(wfd==-1){
        perror("open");
        exit(1);
    }
	cout <<"wfd = " <<wfd <<endl;

    while(1)
	{
        printf("server: ");
		memset(buf, 0, sizeof(buf));
		int rLen = 0;
        if((rLen = read(rfd,buf,1024))<0)
		{
            perror("read");
            exit(1);
        }
		CMemOp kMemOp;
		kMemOp.InitRead(buf, rLen);
		cout <<kMemOp.ReadInt() <<endl;
		cout <<kMemOp.ReadInt() <<endl;
		//cout <<buf <<endl;

       /* if(strcmp(buf,"exit")==0)
		{
            exit(0);
        }
*/
		memset(buf, 0, sizeof(buf));
        printf("client:");
        scanf("%s",buf);
        write(wfd,buf,strlen(buf));
    }
}


编译比较简单 g++ -o server server.cpp

g++ -o client client.cpp

首先运行./client



再运行./server



另外有一个问题,在最后说一下,通常创建管道时,不成功而且提示 operation not permited 也是权限不允许,这时候就检查一下目录权限

为什么/gyl/这个目录可以呢 ,可以看下一张图



可以看到这个目录是 drwxrwxrwt 权限,其他目录下不成功,得加上这个权限



具体方法如上

管道通信的功能还是没有socket通信那么功能强大而且灵活,既然是管道,数据只能从一头流向另向另一头,要想从另一头将数据流回当前这头,又得多一条管道。

在读写有名管道之前需要用open函数打开该有名管道,打开有名管道操作与其他文件有一定的区别,如果希望打开管道的写端,则需要另一个进程打开该管道的读端,如果只打开有名管道的一端,则系统将暂时阻塞打开进程,知道另一个进程打开管道的另一端,当前进程才会继s续执行,因此,在使用有名管道时一定么使用两个进程分别打开其读端和写端!

这是为什么要先启client ,因为最开始的读端在client上,如果不先启动client ,server 的写端一直阻塞在那里,先启动client 就能保证正常运行。

参考的一些文章
http://blog.csdn.net/jmy5945hh/article/details/7528395 http://www.cnblogs.com/TsengYuen/archive/2012/05/16/2504102.html http://blog.chinaunix.net/uid-26983585-id-3345105.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: