进程间通信(5) - 命名管道(FIFO)

1. 前言

本篇文章的所有例子,基于RHEL6.5平台。前一篇文章介绍了匿名管道。点此链接

2.介绍

管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。

POSIX标准中的FIFO又名有名管道或命名管道。我们知道前面讲述的POSIX标准中管道是没有名称的,所以它的最大劣势是只能用于具有亲缘关系的进程间的通信。FIFO最大的特性就是每个FIFO都有一个路径名与之相关联,从而允许无亲缘关系的任意两个进程间通过FIFO进行通信。

所以,FIFO的两个特性:

**和管道一样,FIFO仅提供半双工的数据通信,即只支持单向的数据流。

**和管道不同的是,FIFO可以支持任意两个进程间的通信。

3.mknod函数

<span style="font-family:Arial;font-size:12px;">#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);</span>

使用方法:  mknod 管道名称 p

4.mkfifo函数

<span style="font-family:Arial;font-size:12px;">#include<sys/types.h>
#include<sys/stat.h>
//成功则返回0,失败返回-1
int mkfifo(const char * pathname,mode_t mode);</span>

使用方法:mkfifo -m 权限 管道名称

参数说明:

pathname:一个Linux路径名,它是FIFO的名字。即每个FIFO与一个路径名相对应。

第二个参数与打开普通文件的open()函数中的mode 参数相同,指定的文件权限位。即创建该FIFO时,指定用户的访问权限,有以下值:S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP,S_IROTH,S_IWOTH。

如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如close、read、write等等。

mkfifo函数默认指定O_CREAT | O_EXECL方式创建FIFO,如果创建成功,直接返回0。如果FIFO已经存在,则创建失败,会返回-1并且errno置为EEXIST。对于其他错误,则置响应的errno值;

当创建一个FIFO后,它必须以只读方式打开或者只写方式打开,所以可以用open函数,当然也可以使用标准的文件I/O打开函数,例如fopen来打开。由于FIFO是半双工的,所以不能够同时打开来读和写。

其实一般的文件I/O函数,如read,write,close,unlink都可用于FIFO。对于管道和FIFO的write操作总是会向末尾添加数据,而对他们的read则总是会从开头数据,所以不能对管道和FIFO中间的数据进行操作,因此对管道和FIFO使用lseek函数,是错误的,会返回ESPIPE错误。

mkfifo的一般使用方式是:通过mkfifo创建FIFO,然后调用open,以读或者写的方式之一打开FIFO,然后进行数据通信。

下面是FIFO的一个简单的测试代码:

<span style="font-family:Arial;font-size:12px;">#include <iostream>  

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

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

using namespace std;  

#define FIFO_PATH "/root/fifo"  

int main()
{
    if (mkfifo(FIFO_PATH, 0666) < 0 && errno != EEXIST)
    {
        cout<<"create fifo failed."<<endl;
        return -1;
    }  

    if (fork() == 0)
    {  

        int readfd = open(FIFO_PATH, O_RDONLY);
        cout<<"child open fifo success."<<endl;  

        char buf[256];  

        read(readfd, buf, sizeof(buf));
        cout<<"receive message from pipe: "<<buf<<endl;  

        close(readfd);  

        exit(0);
    }  

    sleep(3);
    int writefd = open(FIFO_PATH, O_WRONLY);
    cout<<"parent open fifo success."<<endl;  

    char *temp = "hello world";
    write(writefd, temp, strlen(temp) + 1);  

    close(writefd);
}</span>

输出:

[[email protected] csdnblog]# ./a.out

parent open fifo success.

child open fifo success.

receive message from pipe: hello world

由上面的运行结果可以看到,子进程以读方式open的操作会阻塞到父进程以写方式open;关于这一点以及read和write的操作会在后面管道和FIFO的属性部分进行介绍;

POSIX标准不仅规定了对mkfifo IPC的支持,还包括了对mkfifo shell命令的支持,所以符合POSIX标准的UNIX中都含有mkfifo命令来创建有名管道。

[[email protected] csdnblog]# mkfifo fifotest

[[email protected] csdnblog]# echo "hello world" > fifotest &

[1] 2726

[[email protected] csdnblog]# cat < fifotest

hello world

[1]+ Done echo "hello world" > fifotest

这里在第二行最后加上‘&’使进程转到后台运行,是因为FIFO以只写方式打开需要阻塞到FIFO以只读方式打开为止,所以必须要作为后台程序运行,否则进程会阻塞在前端,无法再进行相关输入。

5.mknod与mkfifo区别

mknod系统调用会产生由参数path所指定的文件,生成文件类型和访问权限由参数mode决定。

在很多unix的版本中有一个C库函数mkfifo,与mknod不同的是多数情况下mkfifo不要求用户有超级用户的权限。

利用命令创建命名管道p1.

#mkfifo -m 0644 p1

#mknod p2 p

#ll

<span style="font-family:Arial;font-size:12px;">#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
main()
{
    if(mkfifo("p1",0644) < 0)
    {
        perror("mkfifo");
        exit(-1);
    }
    return;
}</span>

6.管道打开规则

有名管道比管道多了一个打开操作:open。

由于在POSIX标准中,管道和FIFO都是通过文件描述符来进行操作的,默认的情况下,对他们的操作都是阻塞的,当然也可以通过设置来使对他们的操作变成非阻塞的。我们都知道可以有两种方式来设置一个文件描述符为O_NONBLOCK非阻塞的:

--调用open时,指定O_NONBLOCK标志。例如:

int fd = open(FILE_NAME, O_RDONLY | O_NONBLOCK);

--通过fcntl文件描述符控制操作函数,对一个已经打开的描述符启用O_NONBLOCK标志。其中对于管道必须使用这种方式。示例如下:

int flag;

flag = fcntl(fd, F_GETFL, 0);

flag |= O_NONBLOCK;

fcntl(fd, F_SETFL, flag);

下图主要说明了对管道和FIFO的各种操作在阻塞和非阻塞状态下的不同,这张图对对于理解和使用管道和FIFO是非常重要的。

从上图我们看到关于管道和FIFO的读出和写入的若干规则,主要需要注意的有以下几点:

· 以只读方式open FIFO时,如果FIFO还没有以只写方式open,那么在阻塞模式下,该操作会阻塞到FIFO以只写方式open为止。

· 以只写方式open FIFO时,如果FIFO还没有以只读方式open,那么在阻塞模式下,该操作会阻塞到FIFO以只读方式open为止。

· 从空管道或空FIFO中read,如果管道和FIFO已打开来写,在阻塞模式下,那么该操作会阻塞到管道或FIFO有数据为止,或管道或FIFO不再以写方式打开。如果管道和FIFO没有打开来写,那么该操作会返回0;

· 向管道或FIFO中write,如果管道或FIFO没有打开来读,那么内核会产生SIGPIPE信号,默认情况下,该信号会终止该进程。

另外对于管道和FIFO还需要说明的若干规则如下:

· 如果请求write的数据的字节数小于等于PIPE_BUF(POSIX关于管道和FIFO大小的限制值),那么write操作可以保证是原子的,如果大于PIPE_BUF,那么就不能保证了。

那么由此可知write的原子性是由写入数据的字节数是否小于等于PIPE_BUF决定的,和是不是O_NONBLOCK没有关系。下面是在阻塞和非阻塞情况下,write不同大小的数据的操作结果:

在阻塞的情况下:

· 如果write的字节数小于等于PIPE_BUF,那么write会阻塞到写入所有数据,并且 写入操作是原子的。

·  如果write的字节数大于PIPE_BUF,那么write会阻塞到写入所有数据,但写入操作不是原子的,即write会根据当前缓冲区剩余的大小,写入相应的字节数,然后等待下一次有空余的缓冲区,这中间可能会有其他进程进行write操作。

在非阻塞的情况下:

· 如果write的字节数小于等于PIPE_BUF,且管道或FIFO有足以存放要写入数据大小的空间,那么就写入所有数据;

·  如果write的字节数小于等于PIPE_BUF,且管道或FIFO没有足够存放要写入数据大小的空间,那么就会立即返回EAGAIN错误。

· 如果write的字节数大于PIPE_BUF,且管道或FIFO有至少1B的空间,那么就内核就会写入相应的字节数,然后返回已写入的字节数;

· 如果write的字节数大于PIPE_BUF,且管道或FIFO无任何的空间,那么就会立即返回EAGAIN错误。

对FIFO打开规则的验证(主要验证写打开对读打开的依赖性)

<span style="font-family:Arial;font-size:12px;">#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#define FIFO_SERVER "/tmp/fifoserver"
int handle_client(char*);
int main(int argc, char** argv)
{
	int r_rd;
	int w_fd;
	pid_t pid;
	if ((mkfifo(FIFO_SERVER, O_CREAT | O_EXCL) < 0) && (errno != EEXIST))
		printf("cannot create fifoserver\n");
	handle_client(FIFO_SERVER);
	return 0;
}
int handle_client(char* arg)
{
	int ret;
	ret = w_open(arg);
	switch (ret)
	{
	case 0:
	{
			  printf("open %s error\n", arg);
			  printf("no process has the fifo open for reading\n");
			  return -1;
	}
	case -1:
	{
			   printf("something wrong with open the fifo except for ENXIO");
			   return -1;
	}
	case 1:
	{
			  printf("open server ok\n");
			  return 1;
	}
	default:
	{
			   printf("w_no_r return ----\n");
			   return 0;
	}
	}
	unlink(FIFO_SERVER);
}
int w_open(char*arg)
//0  open error for no reading
//-1 open error for other reasons
//1  open ok
{
	if (open(arg, O_WRONLY | O_NONBLOCK, 0) == -1)
	{
		if (errno == ENXIO)
		{
			return 0;
		}
		else
			return -1;
	}
	return 1;
}</span>

输出:

[[email protected] csdnblog]# ./a.out

open /tmp/fifoserver error

no process has the fifo open for reading

7.管道读写规则

通过open打开,默认是阻塞方式打开,如果open指定O_NONBLOCK则以非阻塞打开。

O_NONBLOCK和O_NDELAY所产生的结果都是使I/O变成非搁置模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会搁置程序动作,直到有数据或写入完成。

它们的差别在于设立O_NDELAY会使I/O函式马上回传0,但是又衍生出一个问题,因为读取到档案结尾时所回传的也是0,这样无法得知是哪种情况;因此,O_NONBLOCK就产生出来,它在读取不到数据时会回传-1,并且设置errno为EAGAIN。

不过需要注意的是,在GNU C中O_NDELAY只是为了与BSD的程序兼容,实际上是使用O_NONBLOCK作为宏定义,而且O_NONBLOCK除了在ioctl中使用,还可以在open时设定。

<span style="font-family:Arial;font-size:12px;">#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
main()
{
    int fd;

    if((fd = open("p1",O_RRONLY,0)) < 0)//只读打开管道
  // if((fd = open("p1",O_WRONLY,0)) < 0)//只写打开管道
    {
        perror("open");
        exit(-1);
    }
    printf("open fifo p1 for write success!\n");
    close(fd);
}</span>

从FIFO中读取数据:

约定:如果一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。

·如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直阻塞。对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。

·对于设置了阻塞标志的读操作说,造成阻塞的原因有两种:当前FIFO内有数据,但有其它进程在读这些数据;另外就是FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,不论信写入数据量的大小,也不论读操作请求多少数据量。

·读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)。

·如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。

注:如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。

向FIFO中写入数据:

约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。

对于设置了阻塞标志的写操作:

·当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。

·当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。

对于没有设置阻塞标志的写操作:

·当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。

·当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写;

对FIFO读写规则的验证:

下面提供了两个对FIFO的读写程序,适当调节程序中的很少地方或者程序的命令行参数就可以对各种FIFO读写规则进行验证。

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#define FIFO_SERVER "/tmp/fifoserver"
int main(int argc, char** argv)
//参数为即将写入的字节数
{
	int fd;
	char w_buf[4096 * 2];
	int real_wnum;
	memset(w_buf, 0, 4096 * 2);
	if ((mkfifo(FIFO_SERVER, O_CREAT | O_EXCL)<0) && (errno != EEXIST))
		printf("cannot create fifoserver\n");
	if (fd == -1)
	{
		if (errno == ENXIO)
			printf("open error; no reading process\n");
	}

	fd = open(FIFO_SERVER, O_WRONLY | O_NONBLOCK, 0);
	//设置非阻塞标志
	//fd=open(FIFO_SERVER,O_WRONLY,0);
	//设置阻塞标志
	real_wnum = write(fd, w_buf, 2048);
	if (real_wnum == -1)
	{
		if (errno == EAGAIN)
			printf("write to fifo error; try later\n");
	}
	else
	{
		printf("real write num is %d\n", real_wnum);
	}
	real_wnum = write(fd, w_buf, 5000);
	//5000用于测试写入字节大于4096时的非原子性
	//real_wnum=write(fd,w_buf,4096);
	//4096用于测试写入字节不大于4096时的原子性

	if (real_wnum == -1)
	{
		if (errno == EAGAIN)
			printf("try later\n");
	}
	return 0;
}

没有任何东西输出:

[[email protected] csdnblog]# ./a.out

// 下面的程序是与上面的程序一起测试写FIFO的规则,第一个命令行参数是请求从FIFO读出的字节数

<span style="font-family:Arial;font-size:12px;">#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#define FIFO_SERVER "/tmp/fifoserver"
main(int argc,char** argv)
{
    char r_buf[4096*2];
    int  fd;
    int  r_size;
    int  ret_size;
    r_size=atoi(argv[1]);
    printf("requred real read bytes %d\n",r_size);
    memset(r_buf,0,sizeof(r_buf));
    fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0);
    //fd=open(FIFO_SERVER,O_RDONLY,0);
    //在此处可以把读程序编译成两个不同版本:阻塞版本及非阻塞版本
    if(fd==-1)
    {
        printf("open %s for read error\n");
        exit();
    }
    while(1)
    {

        memset(r_buf,0,sizeof(r_buf));
        ret_size=read(fd,r_buf,r_size);
        if(ret_size==-1)
            if(errno==EAGAIN)
                printf("no data avlaible\n");
        printf("real read bytes %d\n",ret_size);
        sleep(1);
    }
    pause();
    unlink(FIFO_SERVER);
}</span>

程序应用说明:

把读程序编译成两个不同版本:

·阻塞读版本:br

·以及非阻塞读版本nbr

把写程序编译成两个四个版本:

· 非阻塞且请求写的字节数大于PIPE_BUF版本:nbwg

· 非阻塞且请求写的字节数不大于PIPE_BUF版本:版本nbw

· 阻塞且请求写的字节数大于PIPE_BUF版本:bwg

· 阻塞且请求写的字节数不大于PIPE_BUF版本:版本bw

下面将使用br、nbr、w代替相应程序中的阻塞读、非阻塞读

验证阻塞写操作:

1 当请求写入的数据量大于PIPE_BUF时的非原子性:

nbr 1000

bwg

2 当请求写入的数据量不大于PIPE_BUF时的原子性:

nbr 1000

bw

验证非阻塞写操作:

3 当请求写入的数据量大于PIPE_BUF时的非原子性:

nbr 1000

nbwg

4 请求写入的数据量不大于PIPE_BUF时的原子性:

nbr 1000

nbw

不管写打开的阻塞标志是否设置,在请求写入的字节数大于4096时,都不保证写入的原子性。但二者有本质区别:

对于阻塞写来说,写操作在写满FIFO的空闲区域后,会一直等待,直到写完所有数据为止,请求写入的数据最终都会写入FIFO;

而非阻塞写则在写满FIFO的空闲区域后,就返回(实际写入的字节数),所以有些数据最终不能够写入。

对于读操作的验证则比较简单,不再讨论。

8.通信模式

命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,消息以一个连续的字节流的形式,在客户机与服务器之间流动。这意味着,对客户机应用和服务器应用来说,在任何一个特定的时间段内,它们不能准确知道有多少字节从管道中读入或者写入管道。因此,在一方写入某个数量的字节,并不表示在另一方会读出等量的字节。这样一来,客户机和服务器在传输数据的时候,便不必关心数据的内容。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发。每次在管道上发出了一条消息后,它必须作为一条完整的消息读入。

命名管道最大的特点便是建立一个简单的客户机/服务器程序设计体系。在这个体系结构中,在客户机与服务器之间,数据既可单向传递,亦可双向流动。这一点相当重要,因为我们可以自由地收发数据,无论应用程序是一个客户机还是一个服务器。对命名管道服务器和客户机来说,两者最大的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。对一个客户机应用来说,它只能同一个现成的命名管道服务器建立连接。在客户机应用和服务器应用之间,一旦建好连接,两个进程都能对标准的Wi n 3 2函数,在管道上进行数据读取与写入。这些包括R e a d F i l e和Wr i t e F i l e等。

要想实现一个命名管道服务器,要求必须开发一个应用程序,通过它创建命名管道的一个或多个“实例”,再由客户机进行访问。对服务器来说,管道实例实际就是一个句柄,用于从本地或远程客户机应用接受一个连接请求。按下述步骤行事,便可写出一个最基本的服务器应用:

1) 使用API函数CreatNamedPipe,创建一个命名管道实例句柄。

2) 使用API函数ConnectNamedPipe,在命名管道实例上监听客户机连接请求。

3) 分别使用ReadFile和WriteFile这两个A P I函数,从客户机接收数据,或将数据发给客户机。

4) 使用API函数DisconnectNamedPipe,关闭命名管道连接。

5) 使用API函数CloseHandle,关闭命名管道实例句柄。

实现一个命名管道客户机时,要求开发一个应用程序,令其建立与某个命名管道服务器的连接。注意客户机不可创建命名管道实例。然而,客户机可打开来自服务器的、现成的实例。下述步骤讲解了如何编写一个基本的客户机应用:

1) 用API函数WaitNamedPipe,等候一个命名管道实例可供自己使用。

2) 用API函数CreatFile,建立与命名管道的连接。

3) 用API函数WriteFile和ReadFile,分别向服务器发送数据,或从中接收数据。

4) 用API函数CloseHandle,关闭打开的命名管道会话

9.管道和FIFO的限制

系统内核对于管道和FIFO的唯一限制为:OPEN_MAX和PIPE_BUF;

OPEN_MAX:一个进程在任意时刻可以打开的最大描述符数。

PIPE_BUF标识一个管道可以原子写入管道和FIFO的最大字节数,并不是管道或FIFO的容量。

关于这两个系统限制,POSIX标准中都有定义的不变最小值:POSIX_OPEN_MAX和_POSIX_PIPE_BUF,这两个宏是POSXI标准定义的编译时确定的值,他们是标准定义的且不会改变的,POSIX标准关于这两个值的限制为:

cout<<_POSIX_OPEN_MAX<<endl;

cout<<_POSIX_PIPE_BUF<<endl;

//运行结果为:

20

512

我们都知道,关于POSIX的每个不变最小值都有一个具体的系统的实现值,这些是实现值由具体的系统决定,通过调用以下函数在运行时确定这个实现值:

#include <unistd.h>

//成功返回具体的值,失败返回-1

long sysconf(int name);

long fpathconf(int filedes, int name);

long pathconf(char *path, int name);

其中sysconf是用于返回系统限制值,这些值是以_SC_开头的常量,pathconf和fpathconf是用于返回与文件和目录相关的运行时的限制值,这些值都是以_PC_开头的常量;

下面是在Linux 2.6.18下的测试代码:

cout<<sysconf(_SC_OPEN_MAX)<<endl;

cout<<pathconf(FIFO_PATH, _PC_PATH_MAX)<<endl;

//运行结果为:

1024

4096

当然上面两个系统限制值的具体实现值也可以通过ulimit命令来查看

[[email protected] program]# ulimit -a

open files                    (-n) 1024

pipe size            (512 bytes, -p) 8

这两个值在Linux 2.6.18下都是不允许修改的,也是没有必要修改的。

时间: 2024-10-05 05:41:09

进程间通信(5) - 命名管道(FIFO)的相关文章

简述Linux进程间通信之命名管道FIFO

上文聊到管道(pipe),可以使有亲缘关系的进程间进行通信. 对于没有亲缘关系的进程如何通信?本文来聊一聊命名管道FIFO. 一.概念 命名管道FIFO,提供一个路径名与之关联,以文件形式存储于文件系统中. 一个进程以r方式打开,另一个程序以w方式打开,即可在两个进程之间建立管道. 通过以fifo文件作为媒介,可以使任意两个进程通过该文件进行通信. 命名管道(fifo)特性与管道(pipe)类似,不必赘述. 下面我们看FIFO如何进行进程间通信,首先来介绍一下所用到的函数: 二.函数原型 #in

Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信: 实现机制: 管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息.一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管

进程间通信之命名管道

命名管道(FIFO)是进程间通信的一种方式,DEMO如下: // 写进程 int main(int argc, char **argv) { char filename[] = "/tmp/my_fifo"; if (mkfifo(filename, 0777) < 0) { perror("mkfifo error"); exit(1); } int fd = open(filename, O_WRONLY); char buffer[128] = &quo

linux中的命名管道FIFO

匿名管道pipe前面已经说过了,接下来就说命名管道FIFO: 我们可以使用以下函数之一来创建一个命名管道,他们的原型如下:#include <sys/types.h>#include <sys/stat.h>int mkfifo(const char *filename, mode_t mode);int mknod(const char *filename, mode_t mode | S_IFIFO, (dev_t)0);这两个函数都能创建个FIFO,   注意是创建一个真实存

Linux下进程间通信之命名管道(FIFO)

匿名管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信.在命名管道(FIFO)提出后,该限制得到了克服.FIFO不同于pipe在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中.命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够相互通信. FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出. Linux下有两种方式创建FIFO,一是在shell下交互的建立一个命名管道,二是在程序中使用系统函

Linux系统编程——进程间通信:命名管道(FIFO)

命名管道的概述 无名管道,由于没有名字,只能用于亲缘关系的进程间通信(更多详情,请看<无名管道>).为了克服这个缺点,提出了命名管道(FIFO),也叫有名管道.FIFO 文件. 命名管道(FIFO)不同于无名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据. 命名管道(FIFO)和无名管道(pipe)有一

进程间通信:命名管道

一.命名管道(FIFO) 匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信.如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道. 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:$ mkfifo filename命名管道也可以从程序里创建,相关函数有:int mkfifo(const char *filename,mode_t mode); 二.命名管道和匿名管道 匿名管道由pipe函数创建并打开.命名管道由mkfifo

Linux进程间通信 -- 使用命名管道

在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程之间交换数据带来了不方便.这里将会介绍进程的另一种通信方式——命名管道,来解决不相关进程间的通信问题. 一.什么是命名管道 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似. 由于Linux中所有

进程间通信IPC-命名管道FIFO

FIFO又被称为命名管道,未命名的管道只能在两个相关的进程之间使用,而这两个相关的进程还要有一个共同创建了它们的祖先进程,但是FIFO,不相关的进程之间也能交换数据. FIFO是一种文件类型.通过stat结构的st_mode成员的编码可以知道文件是否是FIFO类型,在linux下查看自己创建的FIFO文件: 创建FIFO类似于创建文件,也存在于文件系统之中.定义如下: #include <sys/stat.h> int mkfifo(const char* path, mode_t mode)