进程间通信之管道

管道(本质是内核的缓存):一个进程到另一个进程的数据流。大小一般为4K。(一页也是4K,高效).

限制:

1.半双工通信

2.只能在有亲缘关系的进程间使用(有公共祖先),通常,一个管道有一个进程创建,然后该进程调用fork,此后父、子进程就可应用该管道。

管道的创建:

int pipe(int fildes[2]);//filedes[0]为读而打开,filedes[1]为了写而打开。 filedes[1]的输出是filedes[0]的输入。

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

简单说明:一般而言,进程退出,管道释放,所以管道的生命周期随进程。

一般而言,内核会对管道操作进行同步与互斥

 

 

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

int main()
{
    //建立管道
    int fds[2];
    if (-1 == pipe(fds)) perror("pipe"), exit(1);
    pid_t pid = fork();
    if(-1 == pid){
        perror("fork");
        exit(1);
    }
    else if(0 == pid)   //子进程读
    {
        close(fds[1]);   //不写
        char buf[1024] = {};
        while(1)
        {
            int r;
            memset(buf, 0x00, sizeof(buf));
            r = read(fds[0], buf, sizeof(buf));
            if(-1 == r)perror("read"), exit(1);
            if(0 == r) break;
            printf("child read = %s\n", buf);
        }
        
    }else  //父进程写
    {
        close(fds[0]);
        char buf[1024] = {};
        while(fgets(buf, sizeof(buf), stdin) != NULL)
        {
            int w;
            w = write(fds[1], buf, strlen(buf));
            if(-1 == w) perror("write"), exit(1);
            memset(buf, 0x00, sizeof(buf));
        }
    }
    return 0;
}

shell管道的实现:

 

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

int main()
{
    //建立管道
    int fds[2];
    if(-1 ==  pipe(fds)) perror("pipe"), exit(1);
    pid_t pid = fork();
    if(-1 == pid){
        perror("fork");
        exit(1);
    }
    else if(0 == pid)//子进程写
    {
        close(fds[0]);  //不读
        close(1);       //关掉标准输出
        dup(fds[1]);    //写到管道的写端
        execlp("ls", "ls", "-l", NULL);
        close(fds[1]);
        printf("替换进程失败\n");

    }else  //父进程读
    {
        close(fds[1]);  //不写
        close(0);       //关掉标准输出
        dup(fds[0]);    //输出到管道的读端
        execlp("wc", "wc", "-l", NULL);
        close(fds[0]);
        printf("替换进程失败\n");
    }
    return 0;
}

命名管道:

管道对操作的进程有个限制,必须具有同一个公共祖先的进才能使用。要是没有任何关系的进程要进行的通信,我们就要使用到命名管道。命名管道是一种特殊的文件类型。

命名管道可以使用命令行创建:

mkfifo  filename

也可以从程序里创建,相关函数为:

int mkfifo(const char* pathname, mode_t mode);              返回值:成功返回0, 出错返回-1         出错的原因一般是创建文件的目录没有写权限。

当没有进程往管道中写时,从管道中读会发生阻塞,当没有进程从管道中读的时候,往管道中写会阻塞。

示例程序1: 打开一个命名管道,write.c程序对管道进行写操作,read.c对管道进行读操作

 

#include <stdio.h>
#include <stdlib.h>            //打开管道

int main()
{
    if(mkfifo("mypipe.p", 0644) == -1)
    {
        perror("mkfifo");
        exit(1);
    }
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>          //写操作

int main()
{
    int fd = open("mypipe.p", O_WRONLY);
    if(-1 == fd)
    {
        perror("open");
        exit(1);
    }
    int i = 1;
    while(1)
    {
        if(-1 == write(fd, &i, sizeof i))
        {
            perror("read");
            break;
        }
        i++;
        printf("write %d ok!\n", i - 1);
        sleep(1);
    }

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>             //读操作

int main()
{
    int fd = open("mypipe.p", O_RDONLY);
    if(-1 == fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        int i;
        if(0 == read(fd, &i, sizeof i))
        {
            printf("pipe close\n");
            break;
        }
        printf("i = %d\n", i);
    }

    return 0;
}

示例程序2:利用命名管道实现文件的拷贝

 

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>              //读操作

int main()
{
    if(-1 == mkfifo("fifo.p", 0644)) perror("mkfifo"), exit(1);
    int infd;
    infd = open("aaa", O_RDONLY);
    
    if(-1 == infd) perror("open"), exit(1);

    int outfd;
    outfd = open("fifo.p", O_WRONLY);
    if(-1 == outfd) perror("open"), exit(1);

    char buf[1024];
    int n;
    while((n = read(infd, buf, 1024)) > 0)
    {
        write(outfd, buf, n);
    }
    close(infd);
    close(outfd);
    
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>                          //写操作

int main()
{
    int outfd;
    outfd = open("COPY", O_WRONLY|O_CREAT|O_TRUNC, 0644);
    if(-1 == outfd) perror("open"), exit(1);

    int infd;
    infd = open("fifo.p", O_RDONLY);
    if(-1 == infd) perror("open"), exit(1);
    
    char buf[1024];
    int n;
    while((n = read(infd, buf, 1024)) > 0)
    {
        write(outfd, buf, n);
    }
    close(infd);
    close(outfd);
    unlink("fifo.p");
    return 0;
}:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值