进程间通信及管道

目录

目录

1.1通信目的:

1.2通信方式

1.3管道

(匿名)管道:所有UNIX都支持这种通信机制,

​ (有/无名)管道特点:     

 匿名管道使用

父子进程读写案例

读写时注意:

   设置管道非阻塞

有名管道 FIFO

 和pipe区别:

FIFO使用       

fifo实现简单的聊天


简介

不同进程之间资源是独立的,不能在一个进程里直接访问另一个进程的资源。他们的信息交互和状态传递需要进程间通信(IPC)。

1.1通信目的:

数据传输:传输数据

通知事件:如子进程终止时要通知父进程

资源共享:需要内核提供互斥和同步机制

进程控制:如Debug进程需要控制拦截另一个进程,并能够及时知道它的状态改变

1.2通信方式

1.3管道

(匿名)管道:所有UNIX都支持这种通信机制,

        如统计一个目录里文件的数目:ls | wc -l    中间的| 是管道符,有两个进程分别执行ls wc,将ls得到的信息传给wc  

 (有/无名)管道特点:     

                1)内核内存里维护的缓冲器,存储能力有限

                2)拥有文件特质:读,写,匿名管道没有文件实体,有名管道有但不存储数据。 可以执行文件操作

                3)一个管道是一个字节流,所以可以不管写入数据块大小,读取任意大小的数据块。

                4)管道传递数据是顺序的。传入啥样传出就是啥顺序。(先入先出)

                5)管道是单向的,半双工通信。

                6)从管道读数据是一次性操作,数据一旦被读就从管道中抛弃,释放空间以写数据。无法使用lseek()随机访问数据。

                7)匿名管道用于有亲缘关系的进程。(因为如父子进程fd指向同一个匿名管道)。

                8)默认是阻塞的,如果没有数据,等着写,满了,等着收。

        逻辑上,管道是一个环形结构。

 匿名管道使用 <unistd.h>

int pipe(int pipefd[2]) 创建一个匿名管道 成功返回0,失败-1 

        pipefd[2]是一个传出参数  pipedfd[0]对应读端,pipefd[1]对应写。

ulimit -a 查看pipe size  默认 8*512bytes =4k=4096

先管道,再fork()。

父子进程读写案例

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
using namespace std;
int main()
{

    //先管道,再fork
    int pipefd[2];
    int ret=pipe(pipefd);
    if(ret==-1)
    {
        perror("pipe:");
        exit(0);
    }
    pid_t pid=fork();
    if(pid>0)
    {   //父进程
      char readbuf[1024]={0};

      close(pipefd[1]);//关闭写端

        while (1)
        {
            read(pipefd[0],readbuf,sizeof(readbuf));
            cout<<"parent "<<getpid()<<" receive : "<<readbuf<<endl;
            bzero(readbuf,1024);//清除buf上次读到的内容      
        }
    }
    else if(pid==0)
    {   //子进程
        char readbuf[1024]={0};

        close(pipefd[0]);//关闭读端
        
        while(1)
        {
            cout<<"i am "<<getpid()<<endl;
            char wrbuf[1024]="i am child";
            write(pipefd[1],wrbuf,strlen(wrbuf));
            sleep(1);
        }
    }
    return 0;
}

读写时注意:

       读管道:

                管道中有数据,read返回实际读到字节数

                管道无数据,   

                        写端计数=0,读完后再读read返回0,类似文件末尾

                        写端计数>0,读完后再读阻塞等待。

        写管道:

                管道没满,write返回实际写入字节数。

                管道满了

                        读端计数=0,写满后进程收到SIGPIPE信号,进程异常终止

                        读端计数>0,wr写满后阻塞等待。

        子/进程或父进程在另一方不写/写满时会处于阻塞状态,即read/write之后的内容不再继续运行。而设置非阻塞后,read write没成功也可以继续向下运行。

   设置管道非阻塞

             int flags=fcntl(fd[0],F_GETFL);

             flags|=O_NONBLOCK;

             fcntl(fd[0],F_SETFL,flags);

                               

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
using namespace std;
int main()
{

    //先管道,再fork
    int pipefd[2];
    int ret=pipe(pipefd);
    if(ret==-1)
    {
        perror("pipe:");
        exit(0);
    }
    pid_t pid=fork();
    if(pid>0)
    {   //父进程
        char readbuf[1024]={0};

        close(pipefd[1]);//关闭写端
        //设置非阻塞
        int flags=fcntl(pipefd[0],F_GETFL);
        flags|=O_NONBLOCK;
        fcntl(pipefd[0],F_SETFL,flags);

        while (1)
        {
            read(pipefd[0],readbuf,sizeof(readbuf));
            cout<<"parent "<<getpid()<<" receive : "<<readbuf<<endl;
            bzero(readbuf,1024);//清除buf上次读到的内容
            sleep(1) ;     
        }
    }
    else if(pid==0)
    {   //子进程
        char readbuf[1024]={0};

        close(pipefd[0]);//关闭读端
        
        while(1)
        {
            cout<<"i am "<<getpid()<<endl;
            char wrbuf[1024]="i am child";
            write(pipefd[1],wrbuf,strlen(wrbuf));
            sleep(2);
        }
    }
    return 0;
}

                                

有名管道 FIFO

        提供了一个路径名,以FIFO的文件形式存在于文件系统中,所以无亲缘关系的进程只要能够访问该路径,就可以彼此通过FIFO通信。 也有一个写入端,读取端,先入先出。被读后数据被抛弃,不支持lseek等文件定位操作。

 和pipe区别:

        FiFO是文件,但内容存在内存里

        使用FIFO的进程退出后,FIFO文件将继续保存在文件系统里便以后使用

        FIFO有名字,可以使不相关进程通信。

FIFO使用       

        1)命令行mkfifo

        2)int mkfifo(const char* pathname,mode_t mode)创建 

                mode和open的一样8进制数, 都是文件权限  

         创建后就可以用操作文件的open close read等操作

fifo通信   

写fifo

#include <sys/types.h>
#include <cstring>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
using namespace std;

int main()
{
    int ret=access("fifo2",F_OK);//判断文件是否存在

     
     if(ret==-1)
     {
        printf("create fifo\n");
        ret=mkfifo("fifo2",0664);//不存在 创建

        if(ret==-1)
        {
            perror("mkfifo");
            exit(0);
        }
     }

     int fd= open("fifo2",O_WRONLY);
     if(fd==-1)
     {
         perror("write open");
         exit(0);
     }
     for(int i=0;i<100;i++)
     {
        char buf[1024];
        sprintf(buf,"i am %d",i);
        write(fd,buf,strlen(buf));
        sleep(1);
     }
    close(fd);
     return 0;
}

 读fifo

#include <sys/types.h>
#include <cstring>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
using namespace std;

int main()
{
    int ret=access("fifo2",F_OK);//判断文件是否存在

     
     if(ret==-1)
     {
        perror("mkfifo");
        exit(0);
    
     }

     int fd= open("fifo2",O_RDONLY);
     if(fd==-1)
     {
         perror("read open");
         exit(0);
     }
     char buf[1024];
     for(int i=0;i<100;i++)
     {
        
       int len=read(fd,buf,sizeof(buf));
       if(len==0)
       {
           printf("write close\n");
           exit(0);
       }
       printf("%s\n",buf);
       bzero(buf,1024);

     }
close(fd);
     return 0;
}

fifo实现简单的聊天  只能读一句写一句。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <iostream>
int main()
{
    //判断存在
    int ret = access("fifo1",F_OK);

    if(ret==-1)
    {
        printf("fifo1文件不存在\n");
        ret=mkfifo("fifo1",0664);
        if(ret==-1)
        {
            perror("mkfifo1");
            exit(0);
        }
    }

    ret=access("fifo2",F_OK);

    if(ret==-1)
    {
        printf("fifo2文件不存在\n");
        ret=mkfifo("fifo2",0664);
        if(ret==-1)
        {
            perror("mkfifo2");
            exit(0);
        }
    }

    //只写  只读分别打开fifo1,2
    
    int fdw = open("fifo1",O_WRONLY);
    if(fdw==-1)
    {
        perror("open");
        exit(0);
    }
    printf("fifo1 打开,等待写入\n");

    int fdr = open("fifo2",O_RDONLY);
    if(fdr==-1)
    {
        perror("open");
        exit(0);
    }
    printf("fifo2 打开,等待读取\n");

    const int N=128;
    char buf[N];
    //循环读写
    while(1)
    {
        memset(buf,0,N);
        fgets(buf,N,stdin);//获取标准输入的数据
        ret=write(fdw,buf,strlen(buf));
        if(ret==-1)
        {
            perror("wirte");
            exit(0);
        }

        memset(buf,0,N);
        ret=read(fdr,buf,N);
        if(ret<=0)
        {
            perror("read");
            exit(0);
        }
        std::cout<<getpid()<<"read: "<<buf<<std::endl;


    }
    close(fdw);
    close(fdr);
    return 0;


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

int main()
{
    //判断存在
    int ret = access("fifo1",F_OK);

    if(ret==-1)
    {
        printf("fifo1文件不存在\n");
        ret=mkfifo("fifo1",0664);
        if(ret==-1)
        {
            perror("mkfifo1");
            exit(0);
        }
    }

    ret=access("fifo2",F_OK);

    if(ret==-1)
    {
        printf("fifo2文件不存在\n");
        ret=mkfifo("fifo2",0664);
        if(ret==-1)
        {
            perror("mkfifo2");
            exit(0);
        }
    }

    //只写  只读分别打开fifo2,1
    int fdr = open("fifo1",O_RDONLY);
    if(fdr==-1)
    {
        perror("open");
        exit(0);
    }
    printf("fifo1 打开,等待读取\n");

    int fdw = open("fifo2",O_WRONLY);
    if(fdw==-1)
    {
        perror("open");
        exit(0);
    }
    printf("fifo2 打开,等待写入\n");

   
    const int N=128;
    char buf[N];
    //循环读写
    while(1)
    {
      
        memset(buf,0,N);
        ret=read(fdr,buf,N);
        if(ret<=0)
        {
            perror("read");
            exit(0);
        }
        std::cout<<getpid()<<"read: "<<buf<<std::endl;
        
        memset(buf,0,N);
        fgets(buf,N,stdin);//获取标准输入的数据
        ret=write(fdw,buf,strlen(buf));
        if(ret==-1)
        {
            perror("wirte");
            exit(0);
        }


    }
    close(fdw);
    close(fdr);
    return 0;


}

注意两个文件里再打开fifo时 ,顺序要一致,实际要等FIFO1,fifo2都打开,才能继续往下运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值