Linux管道通信

1:匿名管道

在linux下,管道是进程之间通信的方法,简单的说就是在两个进程之间建立一个通道,也就是将一个进程的输入和另一个进程的输出联系起来形成单向通道,这种方法在Linux是最古老最广泛的一种。

在linux中,创建管道的方法是使用系统调用pipe(),如:

int  fd[2];

pipe(fd);

一般只能用于父子进程之间进行通信。

在创建了以后,其在fd[0]是作为读取的描述符,fd[1]是作为写的描述符。也就是通过fd[1]来写,而通过fd[0]来读。

当然了在创建了以后,其进程同时具有对fd[1]和fd[0]的操作。

如果在两个进程之间只进行单向通信,那么应该在两进程之间关闭其中一个,一构成具体的管道。

如在A进程中关闭fd[0],那么在B进程中就关闭fd[1],这样就构成了一个单向通道。B进程写,A 进程读。

如果要创建一个双向的通道,就创建两个通道,一个作为读一个作为写。当然了只创建一个也可以,只要不关闭任意的就可以。但是这样在读取数据时,就分不清来至哪个进程。

创建了两个通道以后,就把每一个通道的描述符互斥关闭。

下面是创建单向通道的例子:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>

void func(){
	printf("func\n");
}

int main(int argv,const char *argc[]){
	pid_t pid;
	int fd[2];
	pipe(fd);//创建管道//
	char* data = "Hello";
	if(pid = fork()){
		//子进程只具有向管道写的功能//
		write(fd[1],data,strlen(data));//向管道写数据//
		close(fd[0]);//关闭子进程的读功能//
		exit(0);
	}
	//父进程只具有从管道读的功能//
	char buf[10] = {0};
	close(fd[1]);//关闭父进程的写功能//
	read(fd[0],buf,10);//从管道中读数据//
	printf("data from child proc %s\n",buf);
	printf("parent proc over\n");
	atexit(func);
	return 0;
}

Run Result:

lingo@lingo-Vostro-470:~/cproject$ ./deamon 
data from child proc Hello
parent proc over
func

2:有名管道(FIFO)

进程间通讯的方式有管道,上面介绍的那种,只适用于有父子关系的进程间通信,但是非父子进程就不能适用上面的管道了。

只能使用有名管道(FIFO),它就是解决非父子进程间通信的方式,当然了我们还知道,尽管管道在 Linux 系统内部是以文件节点(inode)的形式存在的,但是由于其对外的不可见性(“无名”性),我们无法创建新的句柄对其进行访问。而有名管道在 Linux 系统中以一种特殊的设备文件的形式存在于文件系统中。这样它不仅具有了管道的通信功能,也具有了普通文件的优点(可以同时被多个进程共享,可以长期存在等等),有效的解决了管道通信的缺点。

使用有名管道(FIFO)就可以在任意两进程之间进行通信了,当然了有一个限制就是必须要是两进程同时打开才可以。

因为有名管道是存在于文件系统中的文件节点,所以我们可以用建立文件节点的方式来建立有名管道。

在Linux下,使用mknod来创建有名管道:

#include  <sys/type.h>  
#inlcude  <sys/state.h>  
#include  <fcntl.h>  
#include  <unistd.h>  
库函数: mknod();  
函数声明: int mknod( char *pathname, mode_t mode, dev_t dev);  
mknod(“/tmp/sampleFIFO”,s_IFIFO|0666,0)  
这条语句在文件系统中建立了一个名为”/tmp/sampleFIFO” 的有名管道,其读写权限是0666(当然,最终的权限还和你的 umask 值有关)。mknod 的第三个参数在创建有名管道

时被忽略,一般都填零。

匿名管道是临时对象,而 FIFO则是文件系统的真正实体,如果进程有足够的权限就可以使用 FIFOFIFO 和匿名管道的数据结构以及操作极其类似,二者的主要区别在于,FIFO 在使用之前就已经存在,用户可打开或关闭 FIFO;而匿名管道只在操作时存在,因而是临时对象。也就是说匿名管道随的生命周期和进程是一样的,而有名管道只要创建以后,生命一直到释放。

一旦FIFO被创建,任何具有适当权限的进程利用标准的open()系统调用加以访问。当用open()调用打开时,一个FIFO和一个匿名管道具有同样的基本功能。即当管道是空的时候,read()调用被阻塞。当管道是满的时候,write()等待被阻塞,并且当用fcntl()设置O_NONBLOCK标志时,将引起read()调用和write()调用立即返回。在它们已被阻塞的情况下,带有一个EAGAIN错误信息。

由此对于FIFO在系统中只要有权限都是可以使用,所以FIFO在无关系进程间通信是非常有用的。

那么既然所有的进程都可以使用管道,那么在写的时候会不会出现数据混乱?幸好系统有这样的规则:一个write()调用可以写管道能容纳(Linux4K字节)的任意字节,系统将保证这些数据是分开的。这表示多个写操作的数据在FIFO文件中并不混合而将被维持分离的信息。

需要注意的是,FIFO必须同时有读/写两个进程端。如果一个进程试图向一个没有读入端进程的FIFO写入数据,一个 SIGPIPE 信号就会产生。这在涉及多个进程的有名管道通信中是很有用的。

例子代码如下:

FIFO1

#include <stdio.h>  
#include <stdlib.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <linux/stat.h>  
  
#define FIFO_FILE "sampleFIFO"  
  
int main(void)  
{  
    int fd;  
    char readbuf[80] = {0};  
    umask(0);  
    //创建FIFO//  
    mknod(FIFO_FILE, S_IFIFO|0666, 0);  
    while(1)  
    {  
        //打开FIFO//  
        fd = open(FIFO_FILE, O_RDONLY);  
        //从FIFO中读取数据//  
        read(fd,readbuf,80);  
        printf("Rece data: %s\n", readbuf);  
        close(fd);  
    }  
    return(0);  
}  

FIFO2

#include <stdio.h>  
#include <stdlib.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <linux/stat.h>  
#include <string.h>  
  
#define FIFO_FILE "sampleFIFO"  
int main(int argc, char *argv[])  
{  
    int fd;  
    if ( argc != 2 ) {  
        printf("USAGE: fifoclient [string]\n");  
        exit(1);  
    }  
    /*打开FIFO,前提是已经创建过了*/  
    if((fd = open(FIFO_FILE, O_WRONLY)) == -1) {  
        perror("fopen");  
        exit(1);  
    }  
    /*向FIFO中写入数据*/  
    write(fd,argv[1],strlen(argv[1]));  
    /*关闭FIFO*/  
    close(fd);  
    return(0);  
}  

Result:这样就可以从fifo2直接传送数据到fifo1了,在控制 台输入:./fifo2  hello

那么fifo1得到的是:Received string: hellon


在使用管道的时候,在打开时会出现阻塞的现象,这主要是因为所谓管道必须在两端都必须打开,否则另一端会阻塞一直到另一端打开。所以在使用时需要两个端都必须打开。







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值