Linux进程通信---管道

管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信后者用于运行于同一台机,器上的任意两个进程间的通信。

管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等

无名管道

1、 数据自己读不能自己写。
2、 数据一旦被读走,便不在管道中存在,不可反复读取。
3、 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
4、只能在有公共祖先的进程间使用管道。
5、管道不是普通的文件,不属于某个文件系统,其只存在于内存中。
6、从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。
7、默认的情况下,从管道中读写数据,最主要的特点就是阻塞问题(这一特点应该记住),当管道里没有数据,另一个进程默认用 read() 函数从管道中读数据是阻塞的。

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

#define INPUT 0 
#define OUTPUT 1

int main()
{
    int fd[2];
    pid_t pid;  
    char buf[256];
    int ret_cnt;

    // 创建无名管道
    // 返回两个文件描述符,fd[0]用于读,fd[1]用于写
    pipe(fd);  

    if((pid = fork()) < 0)
    {
        printf("Error in fork\n");
        exit(1);
    }

    if(pid > 0) // 父进程
    {
        wait(0); 
        printf("parent\n");

        ret_cnt = read(fd[INPUT], buf, sizeof(buf));

        printf("%d bytes of data recevied from child\n", ret_cnt);
        exit(0);
    }
    else  // 子进程
    {

        printf("child\n");

        write(fd[OUTPUT], "test data", strlen("test data"));
    }

    return 0;
}

这里写图片描述

有名管道

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

写端

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

#define BUF_SIZE PIPE_BUF

int main()
{
    char buf[BUF_SIZE+1] = "Hello word!";

    if(access("/tmp/fifo.txt", F_OK) == -1)  // 如果不存在
    {
        // 创建 有名管道
        // int mkfifo( const char *pathname, mode_t mode);
        // pathname: 普通的路径名,也就是创建后 FIFO 的名字
        // mode: 文件的权限,与打开普通文件的 open() 函数中的 mode 参数相同
        // 返回值:成功:0; 失败:如果文件已经存在,则会出错且返回 -1
        int rt = mkfifo("/tmp/fifo.txt", 0777);  
        if(rt != 0)
        {
            fprintf(stderr, "Could not create fifo %s\n", "/tmp/fifo.txt");
            exit(EXIT_FAILURE);
        }
    }

    printf("Process %d opening FIFO O_WRONLY\n", getpid());
    int fd = open("/tmp/fifo.txt", O_WRONLY);  // 打开

    int bytes = 0;
    if(fd != -1)
    {
        bytes = write(fd, buf, strlen(buf));  // 写入

        if(bytes == -1)
        {
            fprintf(stderr, "Write error on pipe\n");
            exit(EXIT_FAILURE);
        }

        close(fd);  // 关闭
    }
    else
    {
        printf("Open failure\n");
        exit(EXIT_FAILURE);
    }

    printf("Process %d finish, %d bytes had been wroten\n", getpid(), bytes);
    return 0;
}

读端

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

#define BUF_SIZE PIPE_BUF

int main()
{
    char buf[BUF_SIZE+1];
    memset(buf, '\0', sizeof(buf));

    printf("Precess %d opening FIFO O_RDONLY\n", getpid());
    int fd = open("/tmp/fifo.txt", O_RDONLY);  // 打开

    int bytes = 0;
    if(fd != -1)
    {
        int cnt = 0;
        do
        {
            cnt = read(fd, buf, BUF_SIZE);  // 读取
            bytes += cnt;

        }while(cnt > 0);

        close(fd);  // 关闭
    }
    else
    {
        exit(EXIT_FAILURE);
    }

    printf("Process %d finished, %d bytes read\n", getpid(), bytes);

    return 0;
}

运行写端,运行了读端后,写端才会结束。
运行读端,运行了写端后,读端才会结束。
这里写图片描述

参考
https://blog.csdn.net/eroswang/article/details/1772350
https://blog.csdn.net/oguro/article/details/53841949
https://blog.csdn.net/tennysonsky/article/details/46315517
https://blog.csdn.net/firefoxbug/article/details/8137762
https://blog.csdn.net/tennysonsky/article/details/46326957

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值