【进程通信】无名管道 and 有名管道

  管道通信分为无名管道有名管道

  无名管道用于父进程和子进程间的通信,有名管道可用于运行于同一系统中的任意两个进程间的通信

管道的特点:

 ①半双工,数据只能向一个方向流动;需要双方通信时,要建立两个管道。

 ②只能用于具有亲缘关系的进程。

 ③单独构成一种独立的文件系统,且只存在于内存中。

 ④数据的读写:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,且总是从缓冲区的头部读出数据。


一、建立无名管道

1. pipe

函数的作用:建立管道

函数的原型:int pipe(int filedes[2]);

头文件:#include <unistd.h>

返回值:成功——返回0

    失败——返回-1

函数的说明:pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。

  管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。必须在系统调用fork( )前调用pipe( ),否则子进程将不会继承文件描述符

示例1

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

int main()
{
    int pipe_fd[2];

    if(pipe(pipe_fd) < 0)
    {
        printf("pipe create error!\n");
        return -1;
    }
    else
    { 
        printf("pipe create success!\n");
    }

    close(pipe_fd[0]);
    close(pipe_fd[1]);
}

运行结果:

pipe create success!

示例2

/*父进程借管道将字符串"hello!\n"传给子进程并显示*/
#include <stdio.h>
#include <unistd.h>

int main()
{
    int filedes[2];
    char buffer[80];
    pipe(filedes);
    if(fork() > 0)
    {
        /*父进程*/
        char s[] = "hello!\n";
        write(filedes[1],s,sizeof(s));
    }
    else
    {
        /*子进程*/
        read(filedes[0],buffer,80);
        printf("%s",buffer);
    }

    return 0;
}

运行结果:

hello!


二、读写无名管道

  管道两端可分别用描述符fd[0]fd[1]来描述,管道的两端固定了任务,即fd[0]只能读,fd[1]只能写。

示例:

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

int main()
{
    int pipe_fd[2];
    pid_t pid;
    char buf_r[100];
    int r_num;

    memset(buf_r,0,sizeof(buf_r));

    /*创建管道*/
    if(pipe(pipe_fd) < 0)
    {
        printf("pipe creat error.\n");
        return -1;
    }

    /*创建子进程*/
    if(0 == (pid = fork()))    //子进程
    {
        printf("\n");
        close(pipe_fd[1]);     //关闭写
        sleep(2);              //确保关闭写端
        if((r_num = read(pipe_fd[0],buf_r,100)) > 0)
        {
            printf("%d numbers read from the pipe is %s.\n",r_num,buf_r);
        }
        close(pipe_fd[0]);
        exit(0);
    }
    else if(pid > 0)
    {
        close(pipe_fd[0]);
        if(write(pipe_fd[1],"hello",5) != -1)
        {
            printf("parent write1 hello!\n");
        }
        if(write(pipe_fd[1],"pipe",5) != -1)
        {
            printf("parent write2 pipe!\n");
        }
        close(pipe_fd[1]);      //关闭写
        sleep(3);               //确保关闭写
        waitpid(pid,NULL,0);    //等待子进程结束
        exit(0);
    }

    return 0;
}

运行结果:

parent write1 hello!
parent write2 pipe!
10 numbers read from the pipe is hellopipe.

三、创建有名管道

1. mkfifo

函数的作用:创建有名管道

函数的原型:int mkfifo(const char * pathname, mode_t mode);

参数:filename:有名管道的名称、路径

          mode:打开方式

头文件:#include<sys/types.h>

             #include<sys/stat.h>

mode:

    O_NONBLOCKFIFO打开的时候

    O_RDONLY:只读

    O_WRONLY:只写

    O_RDWR:可读写

返回值:成功——返回0

             失败——返回-1

示例(有名管道的创建):

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO "/tmp/2"

int main()
{
    char buffer[80];
    int fd;

    unlink(FIFO);
    mkfifo(FIFO,0666);

    if(fork() > 0)
    {
        char s[] = "hello!\n";
        fd = open(FIFO,O_WRONLY);
        write(fd,s,sizeof(s));
        close(fd);
    }
    else
    {
        fd = open(FIFO,O_RDONLY);
        read(fd,buffer,80);
        printf("%s",buffer);
        close(fd);
    }

    return 0;
}

运行结果:

hello!


读有名管道:
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIFO "myfifo"

int main(int argc, char **argv)
{
    char buf_r[100];
    int fd;
    int nread;

    /*创建管道*/
    if((mkfifo(FIFO, O_CREAT | O_EXCL) < 0) && (errno != EEXIST))
    {
        printf("cannot cret fifoserver.\n");
    }

    printf("Preparing for reading bytes...\n");

    memset(buf_r,0,sizeof(buf_r));

    /*打开管道*/
    fd = open(FIFO, O_RDONLY | O_NONBLOCK, 0);
    if(-1 == fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        memset(buf_r,0,sizeof(buf_r));

        if(-1 == (nread = read(fd,buf_r,100)))
        {
            if(errno == EAGAIN)
            {
                printf("no data yet\n");
            }
        }
        printf("read %s from FIFO\n",buf_r);
        sleep(1);
    }

    puse();
    unlink(FIFO);
}
写有名管道:
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIFO_SERVER "myfifo"

int main(int argc, char **argv)
{
    char w_buf[100];
    int fd;
    int nwrite;

    /*打开管道*/
    fd = open(FIFO_SERVER, O_WRONLY | O_NONBLOCK, 0);
    if(1 == argc)
    {
        printf("Please send something.\n");
        exit(-1);
    }

    strcpy(w_buf,argv[1]);

    if((nwrite = write(fd,w_buf,100)) == -1)
    {
        printf("The FIFO has not been read yet.Please try later.\n");
    }
    else
    {
        printf("write %s to the FIFO.\n",w_buf);
    }
}
同时运行读和写,运行结果如下:
写:
/*命令行参数hello*/
./write_mkfifo hello
运行结果:
write hello to the FIFO.
读:
Preparing for reading bytes...
read  from FIFO
read  from FIFO
read  from FIFO
read hello from FIFO
read  from FIFO
read  from FIFO
read  from FIFO
read  from FIFO
read  from FIFO
read  from FIFO

管道的应用场景:

1. shell中时常用到管道(作为输入输出的重定向)

2. 用于具有亲缘关系的进程间通信,用户自己创建管道,并完成读写操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值