设为首页 加入收藏

TOP

进程间通信(IPC)(一)
2023-07-23 13:34:36 】 浏览:62
Tags:程间通 IPC

进程间通信(Interprocess Communication,IPC)是指两个或者多个进程之间进行数据交换的过程 进程拥有独立的内存空间

类别

简单进程间通信

  • 命令行参数(向子进程传递和exec系列函数)
    • 这里可以这么理解:在创建子进程的时候,命令行参数是共享的
    • 可以通过fork 的返回值,传递
  • 环境列表 (子进程继承父进程的环境列表和exec系列函数)
  • 信号 (信号本身就是一个数据,不同的信号表示不同的数据,sigqueue还可以携带信号附加值)
  • 文件 (文件就不赘述,Linux下万物皆文件)

传统进程间通信

  • 管道

    • 这里管道又可以细分为有名管道和无名管道
    • 有名管道
    # mkfifo fifo
    # echo 要写入的数据 > fifo
    # cat fifo
    # 管道本身不存储数据。可以当成水管来理解
    # 水桶(文件)才是存放数据的容器
    # 水管是负责运输,并且一根水管不可能同时做到往水桶里加水和取水 
    
    • 编程模型
    步骤 进程A 函数 进程B 步骤
    1 创建管道 mkfifo ----
    2 打开管道 open 打开管道 1
    3 读写管道 read/write 读写管道 2
    4 关闭管道 close 关闭管道 3
    5 删除管道 unlink
    • 无名管道 只适用于父子进程之间的通信
#include <unistd.h>
int pipe(int pipefd[2]);
//成功返回0   失败返回-1
pipefd[2]  作为输出参数 
  • 编程步骤:

    • 通过输出参数pipefd得到两个文件描述符,其中 pipefd[0]用于读,pipefd[1]用于写
    • pipe函数在内核中创建管道文件,并打开两次,一次读,一次写
    • 需要在fork之前调用pipe函数
    • 调用fork创建子进程
    • 父子进程只允许使用无名管道的一端(如果进程想读,则必须关闭写,如果想写,则必须关闭读)
    • 写数据的进程关闭读端(pipefd[0]),读数据的进程关闭写端(pipefd[1])
    • 父子进程传输数据
    • 父子进程分别关闭自己的文件描述符
  • 内存映射(mmap)

    • mmap/munmap底层不维护任何东西,只是返回一个首地址,所分配内存位于堆中
    • brk/sbrk底层维护一个白板纸地,记录所分配内存的结尾位置,所分配内存位于堆中,底层调用mmap/munmap
    • malloc底层维护一个双向链表和必要的控制信息,不可越界访问,所分配内存位于堆中,底层调用brk/sbrk
    • 每个进程都有虚拟的内存空间,虚拟内存地址只是一个数字 ,并没有和实际的物理内存将关联
    • 所谓内存分配与释放,其本质就是建立或者取消虚拟内存和物理内存之间的映射关系
  #include <sys/mman.h>
  //虚拟内存映射到物理内存或者文件
  void *mmap(
      void *addr,     //虚拟内存起始位置,如果为NULL则系统自动选定合适的虚拟内存,成功则返回 一般给NULL
      size_t length,  //映射长度,以字节为单位,自动按照(4K)页对齐
      int prot,       //映射权限
      int flags,      //映射标志
      int fd,         //文件描述符,如果映射到文件则需要指定  如果不是映射到文件(匿名映射)则给0即可
      off_t offset    //文件偏移量,自动按照页(4k)对齐
  );
  /*
  成功返回映射区内存的起地址,失败返回-1 (MAP_FAILED)
  prot  权限取值:
  PROT_EXEC  -  映射区可执行
  PROT_READ  -  映射区可读
  PROT_WRITE -  映射区可写
  PROT_NONE  -  映射区不可访问
      如果既需要读,也需要写,则  PROT_READ|PROT_WRITE
  flags  映射标志:
  MAP_FIXED          - 若在addr内存地址上无法创建映射,则失败(无此标志系统会自动调整合适位置)
  MAP_SHARED         - 对映射区域的写入操作直接写入到文件中
  MAP_PRIVATE        - 对映射区的写入操作只写入到缓冲区中,不会真正写入到文件
  MAP_ANONYMOUS      - 匿名映射  将虚拟内存映射到物理内存而非文件    忽略fd 和 offset参数
  MAP_DENYWRITE      - 拒绝其它对文件的写入操作
  MAP_LOCKED         - 锁定映射区域,保证其不被置换
      一定需要 MAP_SHARED 和 MAP_PRIVATE  二选一
  */
      
  //取消内存映射    
  int munmap(void *addr,size_t length);

XSI进程间通信

IPC标识

  • 内核为每个进程间通信维护一个结构体形式的IPC对象
  • 该IPC对象可通过一个非负整数的IPC标识来引用
  • 与 文件描述符不同,IPC标识在使用时会持续加1,当达到最大值时,向0回转
  • 非负整数,唯一标识一个进程间通信的IPC对象

IPC键值

  • IPC标识是IPC对象的内部名称(编号)
  • 若多个进程需要在同一个IPC对象上会合(使用同一个进程间通信渠道),则必须通过键值作为其外部名称来引用该IPC对象,IPC键值外部名称
  • 无论何时,只要创建IPC对象,就必须指定个键值
  • 键值的数据类型在sys/types.h头文件中被定义为key_t类型,其原始类型就是长整型

两个进程如何在同一个IPC对象上汇合

  • 方式一: 服务器进程以PIC_PRIVATE为键值创建一个新的IPC对象,并将该IPC对象的标识存放在某外(如文件中),客户端进程就只可以去该文件中读取
  • 方式二: 在一个公共头文件中,定义一个两个进程都认可的键值,服务器进程用此键值创建IPC对象,客户端进程用该键值获取 IPC对象
  • 方式三: 两个进程事先约定好一个路径名和一个项目ID(0-255),通过路径名和ID调用ftok函数,将二者转换为一个唯一的键值
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname,int pro_id);
pathname   -  一个真实存在的文件或者目录的路径名
pro_id     -  项目ID,低8位有效,其值域[0,255]
    
   成功返回键值,失败返回-1
    
注意:起作用的是pathname参数所表示的路径,而非pathname字符串本身

实现方式

  • 共享内存

    基本特点:
    • 两个或者更多的进程,共享同一块系统内核负责维护的内存区域,其地址空间通常被映射到堆栈之间
    • 无需复制信息(数据),最快的一种IPC机制
    • 需要考虑同步访问的问题
    • 内核为每个共享内存,维护一个shmid_ds结构体形式的共享内存对象
    #include <sys/types.h>
    #include <sys/shm.h>
    
    //1.创建/获取共享内存     内核维护
    int shmget(key_t key,size_t size,int shmflg);
    /*
    	A.以参数key作为键值创建共享内存,如果共享内存已经存在,则获取该共享内存
    	B.size参数指定共享内存的大小(单位字节),建议取4096的整数倍
    		若希望创建共享内存,则必须指定size参数
    		若只是获取已有的共享内存,则size参数可以传递0
    	C.参数shmflg标识
    		0	-  获取,如果共享内存不存在则获取失败
    		IPC_CRE
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇cobbler 下一篇Linux:进程模型和进程管理

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目