Linux进程间通信-命名管道

前面我们讲了进程间通信的一种方式,匿名管道。
我们知道,匿名管道只能用于父子关系的进程之间。那么没有这种关系的进程之间该如何进行数据传递呢?

1.什么是命名管道

匿名管道是在缓存中开辟的输出和输入文件流的空间,只能用于父子关系的进程之间。因为父子进程的输入和输出文件描述符是一致的。
命名管道是一种实际存在的FIFO文件,称作“管道文件”,用于不同进程之间,命名管道进程间打开同一个FIFO文件,进行数据传递。
我们可以像普通文件一样操作FIFO文件。
不同进程,引用同一个FIFO文件,进行数据传递。

2.创建命名管道
mkfifo函数:创建一个命名管道

int mkfifo(const char *filename,mode_t mode);

filename:指定FIFO文件的名称
mode:指定文件的读写权限

3.访问命名管道
打开FIFO文件有四种方式:

open(const char *filename,O_RDONLY);
open(const char *filename,O_RDONLY|O_NONBLOCK);
open(const char *filename,O_WRONLY);
open(const char *filename,O_WRONLY|O_NONBLOCK);

需要注意的是,不能以O_RDWR模式打开FIFO文件,
因为这样一个进程写入的数据会被该进程读取,FIFO一般只用做单向的数据传递。

open函数的第二个参数,表示是读管道,还是写管道。
O_NONBLOCK表示FIFO管道的读写是非阻塞的,默认的话,是阻塞的。
那么何为阻塞呢?
一个进程写模式打开管道的时候,必须有另一个进程以读模式打开;
或读模式的时候,必须有另一个进程写写模式打开,否则该进程open函数阻塞,直到满足以上关系。

非阻塞,意味着open函数会立即返回,若没有其他进程以只读方式打开,open返回-1,并且FIFO也不会被打开。

4.FIFO管道使用示例
下例有两个程序,fifowrite.c和fiforead.c分别写管道和读管道。
fifowrite.c中将一个文本文件data.txt,写到管道。
fiforead.c中从管道读取数据,并写到dataformfifo.txt文件中。
程序使用了默认的阻塞模式。
示例代码如下:

fifowrite.c

#include<sys/types.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
#include<limits.h>
int main()
{
    const char *fifo_name = "/tmp/my_fifo";
    int pipe_fd = -1;
    int data_fd = -1;
    int res = 0;
    const int open_mode = O_WRONLY;
    char buffer[PIPE_BUF+1];
    if(access(fifo_name,F_OK)==-1)
    {
        res = mkfifo(fifo_name,0777);
        if(res!=0)
        {
            fprintf(stderr,"could not create fifo\n");
            exit(EXIT_FAILURE);
        }
    }
    printf("process %d opening fifo O_WRONLY\n",getpid());
    pipe_fd = open(fifo_name,open_mode);
    data_fd = open("data.txt",O_RDONLY);
    printf("process %d result %d\n",getpid(),pipe_fd);
    if(pipe_fd!=-1)
    {
        int bytes_read = 0;
        bytes_read = read(data_fd,buffer,PIPE_BUF);
        while(bytes_read>0)
        {
            res = write(pipe_fd,buffer,bytes_read);
            if(res==-1)
            {
                fprintf(stderr,"write error\n");
                exit(EXIT_FAILURE);
            }
            bytes_read = read(data_fd,buffer,PIPE_BUF);
            buffer[bytes_read]=‘\0‘;
        }
        close(pipe_fd);
        close(data_fd);
    }
    else{
        exit(EXIT_FAILURE);
    }
    printf("process %d finished.\n",getpid());
    exit(EXIT_SUCCESS);
}

fiforead.c

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<limits.h>
int main()
{
    const char *fifo_name = "/tmp/my_fifo";
    int pipe_fd = -1;
    int data_fd = -1;
    int res = 0;
    int open_mode = O_RDONLY;
    char buffer[PIPE_BUF+1];
    int bytes_read = 0;
    int bytes_write = 0;
    memset(buffer,‘\0‘,sizeof(buffer));

    printf("process %d opening FIFO O_RDONLY\n",getpid());
    pipe_fd = open(fifo_name,open_mode);
    data_fd = open("dataformfifo.txt",O_WRONLY|O_CREAT,0644);
    printf("process %d result %d\n",getpid(),pipe_fd);
    if(pipe_fd!=-1)
    {
        do{
            res = read(pipe_fd,buffer,PIPE_BUF);
            bytes_write = write(data_fd,buffer,res);
            bytes_read +=res;
        }while(res>0);
        close(pipe_fd);
        close(data_fd);
    }
    else{
        exit(EXIT_FAILURE);
    }
    printf("process %d finished,%d bytes read\n",getpid(),bytes_read);
    exit(EXIT_SUCCESS);
}

输出结果:

我们在shell中输入命令 ls -l /tmp/my_fifo查看FIFO管道文件的属性

可以看到,FIFO文件生成了,第一个字符‘p’,表示该文件是一个管道文件。

5.多个进程同时写管道
当多个进程同时写管道时,读管道取得的数据是杂乱的。
此时,我们可以控制每个进程,当要写入的数据超过某个大小时,才写管道,另外要以阻塞的方式打开FIFO。确保写操作的原子性。

时间: 2024-10-06 00:07:02

Linux进程间通信-命名管道的相关文章

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

1.命名管道的特点: (1)是管道,可用于非血缘关系的进程间的通信 (2)使用命名管道时,梁金成需要用路径表示通道. (3)命名管道以FIFO的文件形式存储于文件系统中.(FIFO:总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出.) (4)命名管道是一个设备文件.(因此进程与创建FIFO的进程没有血缘关系,也可以通过访问路径进行通信.) 2.命名管道的创建:(创建命名管道的系统函数有两个:mknod和mkfifo) 头文件:(两个函数均在该头文件中) #include<sys/

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

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

Linux内核源代码情景分析-进程间通信-命名管道

建立命名管道,mknod mypipe p.命名管道存在硬盘上,而管道不是. 通过open打开这个命名管道,在内核中通过sys_open()实现,filename是"***/mypipe ". 相关部分,请参考Linux内核源代码情景分析-文件的打开. sys_open进入filp_open,然后在open_namei中调用一个函数path_walk(),根据文件的路径名在文件系统中找到代表这个文件的inode.在将磁盘上的inode读入内存时,要根据文件的类型(FIFO文件的S_IF

Linux进程间通信:管道

提到进程间通信,我们需要先了解一下进程是什么: 其实在Linux下,早期的Linux为了实现多个程序之间的交替操作,出现了进程的概念.为的就是维护操作系统整个的运行逻辑.并发就是进程间的交替执行. 进程是程序的动态实例. 进程并发运行的环境中,多个进程之间存在如下竞争和合作的关系: -          进程中的资源争用(间接作用) 当并发进程竞争使用同一个资源时,它们之间就会发生冲突.为了避免冲突,当一个进程获得资源时,另一个进程必须等待.这种情况需要通过互斥机制来解决. -         

进程间通信——命名管道

概念 管道一个不足之处是没有名字,因此只能用于具有亲缘关系的进程间通信,命名管道(named pipe或FIFO)解决了这一问题. FIFO提供一个路径名与之关联,以FIFO文件的形式存储于文件系统中.文件系统中路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道. 对文件系统来说,匿名管道(管道)是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信.而命名管道是一个可见的文件,因此,他可以用于任意两个进程间进行通信,不管这两个进程是不是父子进程,也不管这两

Linux - 进程间通信 - 匿名管道

一.概念:进程间通信( IPC,InterProcess Communication) 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进城之间要交换数据必须通过内核, 在内核中 开辟一块缓冲区进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内接提供的这种机制成为进程间 通信(IPC,InterProcess Communication). 二.管道 管道分为匿名管道和命名管道,这里我们只讲匿名管道,命名管道的实现将在下一篇文章中分享.

Windows进程间通信--命名管道

1.相关概述 命名管道(Named Pipes)是一种简单的进程间通信(IPC)机制.命名管道可以在同一台计算机的不同进程之间,或者跨越一个网络的不同计算机的不同进程之间的可靠的双向或单向的数据通信. 命名管道利用了微软网络提供者(MSNP)重定向器,因此无需涉及底层的通信协议等细节.命名管道是围绕windows文件系统设计的一种机制,采用"命名管道文件系统"(Named Pipe File System,NPFS)接口.因此,客户端和服务端均可以使用标准的WIN32文件系统API函数

linux 进程间通信-有名管道(FIFO)

有名管道(FIFO) 命名管道也被称为FIFO文件,是一种特殊的文件.由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一. (1)创建命名管道 用如下两个函数中的其中一个,可以创建命名管道. #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *filename, mode_t mode); int mknod(const char *filename, mode

Linux 进程间通信之管道(pipe),(fifo)

 无名管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信: 定义函数: int pipe(int filedes[2]) filedes[0]为管道里的读取端 filedes[1]则为管道的写入端. 实现机制: 管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息.一个缓