Linux多进程开发——进程间通信 有名管道

有名管道(FIFO)
  • 相关概念

    • 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道,FIFO文件。

    • 有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之相关联,以FIFO的文件形式存在于文件系统中,并且打开方式与打开一个普通文件是一样的,这样即使与FIFO的创建进程不存在亲缘关系的进程,只要访问该路径,就能彼此通过FIFO互相通信,因此,通过FIFO不相关的进程也能交换数据。

    • 一旦打开了FIFO,就能在它上面使用与操作匿名管道和其他文件的系统调用一样的I/O系统调用了。与管道一样,FIFO也有一个读端和写端,并且从管道中读取数据的顺序与写入的顺序是一样的。

    • 有名管道和匿名管道的区别:

      • FIFO在文件系统中作为一个特殊文件存在,但FIFO中的内容却存放在内存中。

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

      • FIFO有名字,不相关的进程可以通过打开有名管道进行通信。

  • 有名管道的使用

    • 通过命令创建有名管道mkfifo 名字

    • 通过函数创建有名管道

      #include<sys/types.h>
      #include<sys/stat.h>
      int mkfifo(const char *pathname,mode_t mode);
      • 参数:

        -pathname:管道名称的路径

        -mode:文件的权限(和open函数的mode是一样的),是一个八进制的数

      • 返回值:成功返回0;失败返回-1,并设置errno

      使用mkfifo创建一个FIFO,就可以使用open打开它,常见的文件I/O函数都可用于FIFO。

      FIFO严格遵守先进先出,对管道及FIFO的读总是从开始处返回数据,对他们的写则是把数据添加到末尾。它们不支持lseek()等文件定位操作。

    • 注意事项

      • 一个为只读而打开一个管道的进程会阻塞,直到另外一个进程为只写打开管道

      • 一个为只写而打开一个管道的进程会阻塞,直到另外一个进程为只读打开管道

利用有名管道实现进程间通信(一个进程读数据,另一个进程写数据):

read.c:读数据

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
​
//从管道中读数据
int main(){
​
    //打开管道文件
    int fd=open("test",O_RDONLY);
    if(fd==-1){
        perror("open");
        exit(0);
    }
​
    //读数据
    while(1){
        char buf[1024]={0};
        int len=read(fd,buf,sizeof(buf));
        if(len==0);{
            printf("写端断开了连接...\n");
            exit(0);
        }
        printf("recv buf: %s\n",buf);
    }
​
    return 0;
}

write.c:写数据

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
​
//想管道中写数据
int main(){
​
    //判断文件是否存在
    int ret=access("test",F_OK);
    if(ret==-1){
        printf("管道不存在,创建管道\n");
​
        //创建管道
        ret=mkfifo("test",0664);
​
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }
    }
​
    //以只写的方式打开管道
    int fd=open("test",O_WRONLY);
    if(fd==-1){
        perror("open");
        exit(0);
    }
​
    //写数据
    for(int i=0;i<100;++i){
        char buf[1024];
        sprintf(buf,"hello,%d\n",i);
        printf("write data : %s\n",buf);
        write(fd,buf,strlen(buf));
        sleep(1);
    }
​
    close(fd);
    return 0;
}

利用有名管道实现聊天功能:

chatA.c

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
​
int main(){
    //1.判断有名管道是否存在
    int ret=access("fifo1",F_OK);
    if(ret==-1){
        //文件不存在
        printf("管道不存在,创建对应的有名管道\n");
        ret=mkfifo("fifo1",0664);
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }
    }
​
    ret=access("fifo2",F_OK);
    if(ret==-1){
        //文件不存在
        printf("管道不存在,创建对应的有名管道\n");
        ret=mkfifo("fifo2",0664);
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }
    }
​
    //2.以只写的方式打开管道1
    int fdw=open("fifo1",O_WRONLY);
    if(fdw==-1){
        perror("open");
        exit(0);
    }
    printf("打开管道fifo1成功,等待写入数据...\n");
​
    //3.以只读的方式打开管道2
    int fdr=open("fifo2",O_RDONLY);
    if(fdr==-1){
        perror("open");
        exit(0);
    }
    printf("打开管道fifo2成功,等待读取...\n");
​
    //4.循环的写、读数据
    char buf[128];
    pid_t pid=fork();
​
    if(pid>0){
        while(1){
            //清空数据
            memset(buf,0,128);
            //获取标准输入的数据
            fgets(buf,128,stdin);
            //写数据
            ret=write(fdw,buf,strlen(buf));
            if(ret==-1){
              perror("write");
              exit(0);
            }
        }
    }else if(pid==0){
        while(1){
            //读数据
            memset(buf,0,128);
            ret=read(fdr,buf,128);
            if(ret==-1){
                perror("read");
                exit(0);
            }
            printf("buf:%s\n",buf);
        }
    }
​
    //5.关闭文件描述符
    close(fdw);
    close(fdr);
​
    return 0;
}

chatB.c

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
​
int main(){
    //1.判断有名管道是否存在
    int ret=access("fifo1",F_OK);
    if(ret==-1){
        //文件不存在
        printf("管道不存在,创建对应的有名管道\n");
        ret=mkfifo("fifo1",0664);
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }
    }
​
    ret=access("fifo2",F_OK);
    if(ret==-1){
        //文件不存在
        printf("管道不存在,创建对应的有名管道\n");
        ret=mkfifo("fifo2",0664);
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }
    }
​
    //2.以只读的方式打开管道1
    int fdr=open("fifo1",O_RDONLY);
    if(fdr==-1){
        perror("open");
        exit(0);
    }
    printf("打开管道fifo1成功,等待读取...\n");
​
    //3.以只写的方式打开管道2
    int fdw=open("fifo2",O_WRONLY);
    if(fdw==-1){
        perror("open");
        exit(0);
    }
    printf("打开管道fifo2成功,等待写入数据...\n");
​
    //4.循环的读、写数据
​
    char buf[128];
    pid_t pid=fork();
    if(pid>0){
        while(1){
            //读数据
            memset(buf,0,128);
            ret=read(fdr,buf,128);
            if(ret==-1){
                perror("read");
                exit(0);
            }
            printf("buf:%s\n",buf);
        }
    }else if(pid==0){
        while(1){
            //清空数据
            memset(buf,0,128);
            //获取标准输入的数据
            fgets(buf,128,stdin);
            //写数据
            ret=write(fdw,buf,strlen(buf));
            if(ret==-1){
                perror("write");
                exit(0);
            }
        }    
    }
​
    //5.关闭文件描述符
    close(fdw);
    close(fdr);
​
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值