进程间通信(一)——管道和FIFO

1. 概述

管道没有名字,适用于有亲缘关系的进程间。

FIFO指first in first out,有一个路径名与之关联,从而允许无亲缘关系的进程间使用。亦称:命名管道named pipe。

两者都是单向数据流(半双工管道),具有随进程的持续性,数据都是先进先出,在进程间通信不需要某种形式的同步。

2.管道

#include <unistd.h>

int pipe(int fd[2]);

返回:成功0,出错-1;

返回两个文件描述符:fd[0]打开来读,fd[1]打开来写。

典型使用:

(1) 单向的

在父子进程间提供通信手段。

父进程创建管道,然后fork出自身的副本。

父进程关闭读端,用于向管道中写。

子进程关闭写端,用于从管道中读。

(2) 双向的

pipe(pipe1[2]);        pipe1[0], pipe1[1]

pipe(pipe2[2]);        pipe2[0], pipe2[1]

fork() == 0 {//子进程

close(pipe1[1]);

close(pipe2[0]);
}

//父进程

close(pipe1[0]);

close(pipe2[1]);

3.pipe例子

下面讲述一个客户——服务器程序。

客户发送路径名,服务器发送文件内容给客户。

#include "unp.h"

void client(int, int), server(int, int);

int main(void)
{
    int pipe1[2], pipe2[2];
    //创建两个管道
    //也会在子进程中创建    Pipe(pipe1);
    Pipe(pipe2);

    int childid = Fork();
    if (childid == 0) {        //child
        Close(pipe1[1]);    //关闭写
        Close(pipe2[0]);    //关闭读

        server(pipe1[0], pipe2[1]);
        exit(0);
    }

    Close(pipe1[0]);
    Close(pipe2[1]);

    client(pipe2[0], pipe1[1]);

    //等待子进程终止
    waitpid(childid, NULL, 0);

    exit(0);
}

server.c代码:

#include "unp.h"
//从管道中读取文件名
//通过管道把文件发送给客户端
void server(int readfd, int writefd)
{
    char buff[MAXLINE + 1];

    ssize_t n = Read(readfd, buff, MAXLINE);
    if (n == 0) {
        err_quit("end-of-file while reading pathname");
    }
    buff[n] = ‘\0‘;

    int fd = open(buff, O_RDONLY);
    if (fd < 0) {
        snprintf(buff + n, sizeof(buff) - n, ": can‘t open, %s\n", strerror(errno));
        n = strlen(buff);
        Write(writefd, buff, n);
    } else {
        while ((n = Read(fd, buff, MAXLINE)) > 0) {
            Write(writefd, buff, n);
        }
        Close(fd);
    }
}

client.c源码:

#include "unp.h"

//从标准输入读入文件路径名,
//通过管道发送给服务器,
//在从管道接受文件的内容写到标准输出
void client(int readfd, int writefd)
{
    char buff[MAXLINE];

    Fgets(buff, MAXLINE, stdin);
    size_t len = strlen(buff);
    if (buff[len - 1] == ‘\n‘) {
        --len;
    }

    Write(writefd, buff, len);

    ssize_t n;
    while((n = Read(readfd, buff, MAXLINE)) > 0) {
        Write(STDOUT_FILENO, buff, n);
    }
}

4.FIFO

与管道最大差别是有名字,适用于无亲缘进程间。

#include <sys/types.h>

#include <sys/stat.h>

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

mkfilo隐含指定O_CREAT | O_EXCL, 要是路径已存在返回EEXIST。

若不想创建一个新的FIFO,可以调用open。

mode类似于open的第二个参数,默认定义FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)。

5.无亲缘关系的客户与服务器

就是上面的客户端发送文件名,服务器端读取文件内容给客户端的在两个独立进程中的写法。

服务器端源码:

#include "unp.h"

void server(int, int);

//服务端创建命名两个管道,
//在一个上open用于读,在另一个上open用于写
int main(void)
{
    //创建时默认O_CREAT | O_EXCL
    //要检测路径是否已经存在,即EEXIST
    if ((mkfifo("/tmp/fifo.1", FILE_MODE)) && (errno != EEXIST)) {
        err_sys("can‘t create /tmp/fifo.1");
    }
    if ((mkfifo("/tmp/fifo.2", FILE_MODE)) && (errno != EEXIST)) {
        //从文件系统中删除路径,也就时FIFO的名字
        //文件的链接计数减1,
        //等到为0时,且没有进程在使用文件时,删除文件
        unlink("tmp/fifo.1");
        err_sys("can‘t create /tmp/fifo.2");
    }

    int readfd = Open("/tmp/fifo.1", O_RDONLY, 0);
    int writefd = Open("/tmp/fifo.2", O_WRONLY, 0);

    server(readfd, writefd);

    exit(0);
}

客户端源码:

#include "unp.h"

void client(int, int);

//打开服务器端已经创建好的管道,
//一个用于读,一个用于写,与服务器端相反
int main(void)
{
    int writefd = Open("/tmp/fifo.1", O_WRONLY, 0);
    int readfd = Open("/tmp/fifo.2", O_RDONLY, 0);

    client(readfd, writefd);

    Close(readfd);
    Close(writefd);

    //由客户端删除管道
    Unlink("/tmp/fifo.1");
    Unlink("/tmp/fifo.2");

    exit(0);
}

server.c 和 client.c参见上面。

注意:

使用FIFO时,必须注意open的顺序。

在没有进程打开FIFO来写,那么打开该FIFO来读的进程将阻塞。

所以在打开FIFO时必须时在一个上读在另一个上写,不能同时打开读然后写。

即open(读);open(写);

open(读);open(写);

会造成死锁,都阻塞在读上。

6. 管道和FIFO额外属性

参见UNPv2 P44,4.7节。

7.一些特性

(1) 向FIFO中write是原子性的操作,一次性写入的东西作为一个整体来看待。

(2) FIFO只能在单台主机上使用的IPC形式。不能用在NFS安装的文件系统中。

(3) 管道是字节流,系统不对它进行解释。

进程间通信(一)——管道和FIFO,布布扣,bubuko.com

时间: 2024-10-23 13:35:30

进程间通信(一)——管道和FIFO的相关文章

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进程间通信-有名管道(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]则为管道的写入端. 实现机制: 管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息.一个缓

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

我们先来说说进程间通信(IPC)的一般目的,大概有数据传输.共享数据.通知事件.资源共享和进程控制等.但是我们知道,对于每一个进程来说这个进程看到属于它的一块内存资源,这块资源是它所独占的,所以进程之间的通信就会比较麻烦,原理就是需要让不同的进程间能够看到一份公共的资源.所以交换数据必须通过内核,在内核中开辟?块缓冲区,进程1把数据从?户空间 拷到内核缓冲区,进程2再从内核缓冲区把数据读?,内核提供的这种机制称为进程间通信.一般我们采用的进程间通信方式有 管道(pipe)和有名管道(FIFO)

进程间通信 ---- 管道与FIFO 用法技巧

1.管道的创建 1.1 mkfifo(const char *pathname,mode_t mode); 函数已隐含指定O_CREAT|O_EXCL,所以它要么创建一个新的FIFO,要么返回EEXIST错误(已存在). 所以在创建已存在FIFO或新的FIFO,应该先调用mkfifo,并检查返回值 是否是EEXIST错误,若是EEXIST错误,则调      用open函数. 2.FIFO或管道读写 2.1对管道或FIFO的write 总是往末尾添加数据,对管道或FIFO的read总是从头开始读

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

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

Linux环境编程之IPC进程间通信(四):管道和FIFO比较

系统加于管道和FIFO的唯一限制是: 1.OPEN_MAX 一个进程在任意时刻打开的最大描述符数.可以通过调用sysconf函数查询. 2.PIPE_BUF 可原子地写往一个管道或FIFO的最大数据量.Posix任务它是一个路径名变量,它的值可以随指定的路径名而变化,因为不同的路径名可以落在不同文件系统上,而这些文件系统可能有不同的特征.所以PIPE_BUF可通过pathconf函数取得. pipeconf.c #include <stdio.h> #include <stdlib.h&

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

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

Linux IPC(Inter-Process Communication,进程间通信)之管道学习

1.标准流管道 管道操作支持文件流模式,用来创建链接还有一个进程的管道,通过函数popen和pclose popen的详细介绍在本blog:Linux 多进程学习中有具体介绍 2.无名管道(PIPE) 特点: 1)仅仅能在亲缘关系进程间通信(父子或兄弟) 2)半双工(固定的读端和固定的写端) 3)是特殊文件,能够用read,write等,在内存中 管道函数原型: #include<unistd.h> int pipe(int fds[2]); 管道在程序中用一对文件描写叙述符表示,一个是可读属