管道(PIPE)和命名管道(FIFO)

1.管道

管道是UNIX系统中最古老的 IPC 方法,管道通常用来在有关系的进程中传递数据,即父子进程间,父孙子进程间,两个子进程间等(由于fork会复制父进程的文件描述符)。管道是一个字节流,也就是说它的数据没有边界(但可以在程序中实现独立的固定大小数据的传输),它可以读或写任意大小的数据,但是数据是按先进先出的顺序传输,而不能进行随机访问(如lseek)。

管道一般用两个文件描述符标记,fd[0]表示读取端,fd[1]表示写入端。进程读取空的管道将会阻塞,直到有数据可读。当管道的写入端关闭时,管道的读取端将读到EOF标志(即不会阻塞,read函数会返回0)。管道的容量为PIPE_BUF(在limits.h中定义的宏,64KB),如果写入大于管道容量大小的数据,将会引起阻塞,直到有空间可写。使用fcntl(fd, F_SETPIPE_SZ, size)可以该变管道的容量(fd即管道的描述符),该函数会返回内核对管道的容量调整后的大小

UNIX标准中,管道是单向的,即只能一端进行读操作(通常会关闭写端),另一端进行写操作(通常会关闭读端)。需要双向通信时,一般需要建立两个管道。

关闭一端的原因:

1.只有当管道的所有文件描述符关闭时,管道才销毁

2.只有当所有读端关闭时,管道满时写端才会收到SIGPIPE信号(默认会关闭进程)

3.只有当所有写端关闭时,管道空时读端才会收到EOF标志


例子:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define BUF_SIZE 5

void err_exit(char *s) 
{
        perror(s);
        exit(-1);
}

int main(int argc, char *argv[])
{
        int pfd[2]; /* 管道描述符 */
        char buf[BUF_SIZE];
        ssize_t numRead;

        if (pipe(pfd) == -1)/* 创建管道 */
                err_exit("pipe");
        switch (fork()) {
        case -1: 
                        err_exit("fork");
        case 0: /* 子进程,读管道 */
                if (close(pfd[1]) == -1) /* 关闭写端 */
                        err_exit("close - child");
                while(1) { 
                        printf("before read\n");
                        numRead = read(pfd[0], buf, BUF_SIZE);
                        if (numRead == -1) 
                                err_exit("child - read");
                        if (numRead == 0)
                                break; /* 读到EOF */
                        printf("%s\n", buf);
                        printf("after read\n");
                }

                write(STDOUT_FILENO, "\n", 1);

                if (close(pfd[0]) == -1)
                        err_exit("close");
                return 0;
        default: /* 父进程,写管道 */
                if (close(pfd[0]) == -1) /* 关闭读端 */
                        err_exit("close - parent");
                if (write(pfd[1], "hello", 5) != 5)
                        printf("parent pipe failed write\n");
                sleep(3);
                if (write(pfd[1], "world", 5) != 5)
                        printf("parent pipe failed write\n");
                if (close(pfd[1]) == -1) /* 子进程将读到 EOF */
                        err_exit("close");
                wait(NULL); /* 等待子进程结束 */
                exit(0);
        }
}

 

2.命名管道(FIFO)

命名管道(FIFO)则是管道的一种变种,它可以在任意进程间传递数。FIFO在文件系统中创建FIFO文件,并拥有文件名。对FIFO的操作,就和操作普通文件一样。

可以在命令行创建FIFO:

$ mkfifo [ -m mode ] pathname

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值