4.进程通信篇(3--有名管道)-2020物联网_Linux高级程序设计全套教程(通俗易懂)

5.09有名管道的概述

pipe指的是无名管道

fifo指的是有名管道

FIFO会在文件系统中直接创建一个可见的文件

linux系统中的文件类型分为7大类 :bcd-lsp

fifo和pipe区别:

1、fifo属于半双工,数据在同一时刻只能在同一个方向上流动

2、写入fifo中的数据遵守先入先出

3、fifo所传送的数据是无格式的,要求读写格式统一

4、fifo在文件系统中作为一个特殊的文件存在,但是fifo 中的内容却在内存中存在

5、管道在内存中对应一个缓冲区

6、从fifo中读取数据是一次性操作

7、当使用fifo的进程退出时,fifo文件将继续保存在文件系统中,释放空间以便写入更加多的数据

8、fifo有名字,不相关的进程可以实现通信

 

5.10有名管道的创建

有两种方式创建:

1、在shell命令中

mkfifo 文件名

2、使用函数mkfifo

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode)

功能:创建一个有名管道,产生一个本地文件系统的文件pathname

参数:文件名和权限;成功返回0

如果文件存在,会报错,我们可以通过查看errno.h中的错误码

#include<errno.h>

{
    if(mkfifo("fifo_file", 0664) == -1)
    {
        if(error != EEXIST)
        {
            这样就可以把文件存在所报的错误给忽略掉
            perror("fail to mkfifo");
            exit(1);
        }
        perror("");
    }
    return 0;
}

5.11有名管道的基本读写操作

系统调用的IO都可以操作FIFO:open,close,read,write等,打开fifo时,非阻塞标志(O_NONBLOCK)产生下列影响;

特点:1、不指定O_NONBLOCK(即open没有位或O_NONBLOCK)

2、open以只读方式打开fifo时,要阻塞多少某个进程为写而打开此fifo

3、open以只写方式打开fifo时,要阻塞多少某个进程为读而打开此fifo

由于有名管道在本地创建了一个管道文件,所以系统调用的IO函数基本都可以对有名管道进行操作,但是不能使用lseek修改管道文件的偏移量

注意:有名管道创建的本地的文件只是起到标识作用,真正有名管道实现进程通信还是在内核空间开辟内存,所以本地产生的文件只是一个标识,没有其他作用。对本地管道文件的操作实质就是对内核空间的操作

4.进程通信篇(3--有名管道)-2020物联网_Linux高级程序设计全套教程(通俗易懂)

#define FIFONAME "fifo_file"

main()
{
    if(mkfifo("fifo_file", 0664) == -1)
    {
        if(error != EEXIST)
        {
            这样就可以把文件存在所报的错误给忽略掉
            perror("fail to mkfifo");
            exit(1);
        }
        perror("");
    }
    接下来就是对有名管道进行操作
    int fd
    fd = open(FIFONAME, O_RDWR);
    if(...) 
    然后就是写数据,读数据
    
    int fd
}                        

 

5.11有名管道如何实现进程间通信

由于有名管道创建了一个管道文件,所以不相关的进程之间可以实现通信,

创建2个有名管道

 

需要一个send.c文件和recv.c

send.c

#include<stdio.h>
#include<stdlib.h>
#include<unstd.h>
...

int main(int argc, char **argv)
{ 
   //创建管道-----if判断出错省略了
   mkfifo("myfifo1", 0664);
   mkfifo("myfifo2", 0664);
   
   int fd_w, fd_r;
   fd_w = open("myfifo1", O_WRONLY);
   fd_r = open("myfifo2", O_RDONLY);
      
   char buf[128] = "";
   ssize_t bytes;
   while(1)
   {
       fgets(buf, sizeof(buf), stdin);
       buf[strlen(buf) -1] = '\0';
       
       bytes = write(fd_w, buf, sizeof(buf));
       bytes = read(fd_r, buf, sizeof(buf));
       printf("from recv:%s\n", buf);
    }  
    
    return 0;
}

 

recv.c
#include<stdio.h>
#include<stdlib.h>
#include<unstd.h>
...

int main(int argc, char **argv)
{ 
    创建管道-----if判断出错
   mkfifo("myfifo1", 0664);
   mkfifo("myfifo2", 0664);
   
   int fd_w, fd_r; //这个地方刚刚好相反
   fd_r = open("myfifo1", O_WDONLY);
   fd_w = open("myfifo2", O_RDONLY);
      
   char buf[128] = "";
   ssize_t bytes;
   while(1)
   {
       bytes = read(fd_r, buf, sizeof(buf));
       printf("from send:%s\n", buf);
       
       fgets(buf, sizeof(buf), stdin);
       buf[strlen(buf) -1] = '\0';   
       bytes = write(fd_w, buf, sizeof(buf));            
    }  
    
    return 0;
}

5.13有名管道的基本读写操作

1、读写端都存在,只读不写

   会发生阻塞

2、读写端都存在,只写不读

   会发生阻塞

3、在一个进程中,只有读端,没有写端

  会在open函数的位置阻塞

4、在一个进程中,只有写端,没有读端

  会在open函数的位置阻塞

 

 

 

 

 

 

 

 

上一篇:Javascript 实现 FIFO


下一篇:先进先出(FIFO)页面置换算法 C语言实现