进程通信之管道

管道

管道是UNIX系统IPC的最古老形式,并且所有UNIX系统都提供此种通信机制,我们把一个进程连接到另一个进程的数据流称为管道,在管道中一个进程写,一个进程读。
这里写图片描述
管道的本质也就是操作系统内核提供的一段内存。

管道在创建时获得固定字节数的大小,当一个进程往里面写时,如果有空间,写请求立即执行,否则该进程被阻塞。类似的,如果一个进程试图读取多于当前管道的字节数时,也会阻塞。

管道有两类:匿名管道和命名管道
匿名管道
匿名管道的操作必须是有两个亲缘关系的进程
管道是调用pipe函数创建的:

int pipe(int fd[2])
fd是一个文件描述符数组,fd[0]表示读端,fd[1]表示写端
成功返回0,失败返回小于0的错误代码

下面一段匿名管道创建的代码:

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

void Test1()
{
    int fd[2];
    int ret = pipe(fd);
    if(ret <  0)
    {
        perror("pipe");
        return;
    }

    //通过fork创建子进程,父进程从管道一端写,子进程从管道读
    int pid = fork();

    const char* str = "hello\n";
    if(pid > 0)
    {
        //father write
        close(fd[0]);//父进程只写,所以关闭读端的文件描述符
        write(fd[1],str,strlen(str));
        close(fd[1]);
        printf("father:%d\n",getpid());
    }
    else if(pid == 0)
    {
        //child read
        close(fd[1]);//子进程只读,所以关闭写端的文件描述符
        char buf[1024] = {0};
        read(fd[0],buf,sizeof(buf)-1);//-1操作是为了给'\0'预留位置
        close(fd[0]);
        printf("child:%d%s\n",getpid(),buf);

    }
    else
        perror("fork");
    sleep(1);
}

用frok共享管道原理:
这里写图片描述

注意:当数据被读走后,数据就会被管道释放,以便继续接收更多的数据。

管道结构
在底层实现总,管道的实现是两个进程的f_inode指向同一个临时的inode节点,这个节点指向一个物理页面
这里写图片描述
因此,对管道的操作也就是对文件的操作,通过不同的文件描述符来标识不同的文件

命名管道
命名管道不需要进程之间有任何关系便能完成通信。
创建一个命名管道:

mkfifo filename

也可以通过函数创建

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

代码实现:
client.c

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

int main()
{
    int ret = open("./mypipe",O_WRONLY);
    if(ret < 0)
    {
        perror("open");
        exit(1);
    }
    char buf[1024] = {0};
    while(1)
    {
        printf(">:");
        fflush(stdout);
        ssize_t read_size = read(0,buf,sizeof(buf)-1);
        if(read_size > 0)
        {
            buf[read_size] = '\0';
            write(ret,buf,strlen(buf));
        }
        else 
        {
            perror("read");
            continue;
        }
    }
    return 0;
}

server.c

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


int main()
{
    int ret = open("./mypipe",O_RDONLY);
    if(ret < 0)
    {
        perror("open");
        exit(1);
    }
    char buf[1024] = {0};
    while(1)
    {
        ssize_t read_size = read(ret,buf,sizeof(buf)-1);
        if(read_size < 0)
        {
            perror("read");
            continue;
        }
        else if(read_size == 0)
        {
            printf("一个客户端退出\n");
            break;
        }
        else
        {
            buf[read_size] = '\0';
            printf("[client]:");
            fflush(stdout);
            write(1,buf,strlen(buf));
        }

    }
    close(ret);
    return 0;
}

mkfifo创建一个命名管道:
用命名管道实现服务器/客户端之间的通信,满足:客户端从标准输入读取信息,通过命名管道发送给服务器端,服务器端将其输出到屏幕上。

管道的特点

  • 单向通信
  • 面向字节流
  • 缓冲区大小有限制
  • 生命周期根随进程
  • 管道有容量限制
  • 管道内部具有同步机制(同时只能由一个进程读写)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值