传统的进程间通信——管道通信

传统的进程间通信——管道通信

  • 管道是UNIX系统中最古老的进程间通信方式,是一种特殊文件读写机制

  • 当进程从管道文件中读取数据时,如果管道中没有数据则进程会进入阻塞状态,直到有数据读取出来才返回,因此不需要借助信号、文件锁来协调读写时间

  • 管道中的数据一旦读取完毕就会消失,因此也不需要管理文件的位置指针,所以使用管道文件比普通文件的进程间通信要方便很多

  • 古老的好处是所有系统都支持,早期的管道文件是半双工,现在有些系统支持管道文件的全双工,现在绝大多数情况已经不使用管道来通信了

有名管道:
  • 在文件系统中创建出一个实体的有文件名的管道文件,然后通过系统I/O的相关API来进行相关操作

使用函数创建:
#include <sys/types.h>
#include <sys/stat.h>
​
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道文件
pathname:管道文件的名字
mode:管道文件的权限
返回值:成功返回0 失败-1
使用命令创建:
mkfifo <file>
管道单向通信的编程模型:
进程A      ->         进程B
创建有名管道      
打开管道              打开管道
写数据                读数据
关闭管道              关闭管道
删除管道                
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
​
int main(int argc,const char* argv[])
{
    //  创建管道文件
    if(mkfifo("fifo",0644))
    {
        perror("mkfifo");
        return -1;
    }
​
    //  打开管道
    int fd = open("fifo",O_WRONLY);
    if(0 > fd)
    {
        perror("open");
        unlink("fifo");
        return -1;
    }
​
    char buf[256] = {};
​
    for(;;)
    {
        printf(">>>");
        //  使用封装好的my_gets()
        gets(buf);
        //  写文件 发送数据
        write(fd,buf,strlen(buf));
        //  检查是否quit
        if(0 == strcmp(buf,"quit"))
        {
            printf("通信结束\n");
            usleep(1000);
            break;
        }
    }
    
    //  关闭管道
    close(fd);
​
    //  删除管道
    unlink("fifo");
}
     
#include <stdio.h>                        
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
​
int main(int argc,const char* argv[])
{
    //  打开管道
    int fd = open("fifo",O_RDONLY);
    if(0 > fd)
    {
        perror("open");
        return -1;
    }
​
    char buf[256] = {};
​
    //  读数据
    for(;;)
    {
        read(fd,buf,sizeof(buf));
        printf("read:%s\n",buf);
​
        if(0 == strcmp(buf,"quit"))
        {
            printf("通信结束\n");
            break;
        }
    }
​
    //  关闭管道
    close(fd);
}
​
​
匿名管道:
  • 只在内核中创建的管道文件对象并返回该对象的文件描述符,然后使用系统IO进行相关操作,匿名管道文件不会在文件系统中显示,在创建时不需要提供路径,也不会占用磁盘空间,只是使用内核空间来临时存储数据,当关闭文件描述符后会自动回收

  • 注意:只适合fork创建的有关系的父子进程之间进行通信

相关API:
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建出匿名管道文件对象,并返回该对象的文件描述符
pipefd:输出型参数,用于存储文件描述符的数组,其中
    pipefd[0]   用于读操作
    pipefd[1]   用于写操作
​
使用步骤:
    1、调用该函数在内核中创建出管道文件,并获取到该文件的两个文件描述符
    2、通过fork创建出子进程,子进程可以直接拷贝父进程的pipefd描述符
    3、写数据的进程要关闭读端,读数据的进程要关闭写端
    4、发送完毕后,父子进程分别关闭文件描述符
编程模型:
    父进程     ->      子进程
   创建匿名管道           
   创建子进程         拷贝一对fd
   关闭读端(fd[0])    关闭写端(fd[1])
   写数据(fd[1])      读数据(fd[0])
   关闭写              关闭读
#include <stdio.h>          
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
​
int main(int argc,const char* argv[])
{
    //  创建匿名管道
    int fd[2] = {};
    if(pipe(fd))
    {
        perror("pipe");
        return -1;
    }
​
    //  创建子进程
    if(fork())
    {
        //  父进程  负责写 关闭读
        close(fd[0]);
        char buf[256] = {};
        for(;;)
        {
            printf("父进程>>>");
            gets(buf);
            write(fd[1],buf,strlen(buf));
            if(0 == strncmp(buf,"quit",4))
            {
                printf("通信结束\n");
                break;
            }
            usleep(1000);
        }
        usleep(1000);
        close(fd[1]);
        usleep(1000);
    }
    else
    {
        //  子进程  负责读 关闭写
        close(fd[1]);
        char buf[256] ={};
​
        for(;;)
        {
            read(fd[0],buf,sizeof(buf));
            printf("read:%s\n",buf);
            if(0 == strncmp(buf,"quit",4))
            {
                printf("父进程要结束通信\n");
                break;
            }
        }
        close(fd[0]);
    }
}                                                                    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值