进程间的通信之管道

管道

  • 本质:连接一个进程和另一个进程之间的数据流,是内核提供的一段内存,通过文件描述符来管理管道。fd[0]读数据,fd[1]写数据
  • 而管道又可分为匿名管道和命名管道两种。

    匿名管道

    int pipe(int pipefd[2])

    这个是匿名管道的创建,用pipe来实现。

  • 匿名管道只能用于具有亲缘关系的进程之间进行通信。一般的时候,一个进程会创建一个管道,然后fork出一个子进程,通过管道进行数据的交流。

  • 这里写图片描述
  • 匿名管道是半双工的(单向通信),如果需要双方通信,则再创建一个管道。
  • 一般来说,进程退出之后,管道机就释放,所以管道的生命周期是随着进程的。内核会对管道进行同步互斥操作。
  • 从内核角度看管道的本质
  • 这里写图片描述

  • 接下来介绍管道的另一种,命名管道

    命名管道

  • 命名管道可以让不想关的进程进行交互,可以应用于任何管道之间

  • 有两种创建方式:在命令行和程序中
  • -

命令行创建
localhost 0801]$ mkfifo filename
//程序中创建
int main(int argc,char *argv[]){
        mkfifo("zyx",0644);//zyx是指向管道读端和写端的指针,0644是读写权限
        int infd;
        infd=open("abc",O_RDONLY);//用open打开读端,读取文件中的文本

        if(infd==-1)
        {
        ERR_EXIT("open");
        }

        int outfd;
        outfd=open("zyx",O_WRONLY);//用open打开写端

        if(outfd==-1)
        {
        ERR_EXIT("open");
        }

        char buf[1024];
        int n;
        while((n=read(infd,buf,1024)>0){//将文本读取到管道之中
        write(outfd,buf,n);//写入管道
        }
        close(infd);
        close(outfd)

//所以,流程为open->read->write->close.这个是通用的
//区别在于从哪里读,往哪里写
  • 还可以用命名管道来实现服务器和客户端的交互
//serevr端
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    umask(0); //允许进程创建文件时有最大权限
    if(mkfifo("mypipe",0644)<0)    
    {
        perror("mkfifo");            
        exit(1);
    }
    int rfd=open("mypipe",O_RDONLY);     //只读模式
    if(rfd<0)
    {
        perror("open");                
        exit(1);
    }

    char buf[1024];                 //缓冲区
    while(1)
    {
        buf[0]=0;
        printf("please wait....\n");   
        ssize_t s=read(rfd,buf,sizeof(buf)-1);  //读取来自客户端的数据到buf中
        if(s>0)
        {
            buf[s-1]=0;                  
            printf("client say # %s\n",buf);//读取成功,可以开始进行交互

        }
        else if(s==0)                    
        {
            printf("server quit");
            exit(0);
        }
        else               
        {
            perror("read");
            exit(1);
        }
    }
    close(rfd);    //关闭读取
    return 0 ;
}


//client端

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

int main()
{

    int wfd=open("mypipe",O_WRONLY);  //只写方式
    if(wfd<0)                        
    {
        perror("open");     
        exit(1);
    }
    char buf[1024];      
    while(1)
    {
        buf[0]=0;             
        printf("please enter#");
        fflush(stdout);   //每次都要刷新,防止数据叠加在一起
        ssize_t s=read(0,buf,sizeof(buf)-1);  //从当前的光标或者键盘输入读入buf中
        if(s>0)
        {              //读取成功
            buf[s]=0;
            write(wfd,buf,sizeof(buf)-1);  //将数据写入buf中
        }
        else if(s<=0)     
        {
            perror("read");    //读取失败
            exit(1);
        }
    }
    close(wfd);   //关闭写入
    return 0 ;
}

结果展示
这里写图片描述

猜你喜欢

转载自blog.csdn.net/Ning_zhi_t/article/details/81351843