Linux进程间通信方式

进程通信

进程间通信(IPC)
进程之间交换数据的过程叫进程间通信

进程间通信方式

一、简单的进程间通信

  • 命令行:父进程通过exec函数创建子进程时可以附加一些数据
  • 环境变量:父进程通过exec函数创建子进程顺便传递一张环境变量表
  • 信号:父子进程可以根据进程号相互发送信号,进程简单通信
  • 命令行、环境变量只能单向传递,信号过于简单,且文件通信不能实时
  • 文件:一个进程向文件中写入数据,另一个进程从文件中读取出来

二、传统进程间通信

管道(fifo)
  管道是一种古老的通信的方式(基本上不再使用) 早期的管道是一种半双工,现在大多数是全双工
有名管道(以文件方式存在)
  • 创建管道文件,命令:mkfifo + file
       int mkfifo(const char *pathname, mode_t mode);
    
  • 管道通信的编程模式
            进程A                   进程B
     创建管道 mkfifo
     打开管道 open                 打开管道
     写/读数据 read/write          写/读数据
     关闭管道close                 关闭管道
     删除管道 unlink/remove
    
无名管道
   (由内核帮助创建,只返回管道的文件描述符),看不到管道文件,只用于fork创建的父子进程之间
    pipefd[0] 用来读数据
    pipefd[1] 用来写数据
    int pipe(int pipefd[2]);

三、XSI IPC进程间通信

  • 每一个IPC对象都有一个IPC标识符(类似于文件描述符),IPC标识是一个非负的整数。IPC对象必须要先创建,创建后才能进程获取、设置、操作、删除。
  • 创建IPC对象必须要提供一个键值(key_t),键值是创建、获取IPC对象的依据
  • 产生键值的方法:
    • 固定的字面值
    • 使用函数计算
    • 键值 = ftok(项目路径,项目id)
    • 使用宏让操作系统随机分配,IPC_PRIATE(随机分配的键值)

必须把获取到IPC对象标识符记录下来,告诉其它进程
XSI可以创建的IPC对象:共享内存、消息队列、信号量

共享内存
  • 由内存维护一个共享的内存区域,其他进程把自己的虚拟地址映射到这块内存,然后多个进程之间就可以共享这块内存
  • 好处:不需要信息复制,是进程间通信最快的一种方式。但这种通信方式会面临同步的问题,需要与其他通信方式配合,最合适的搭配对象为信号。

共享内存的编程模式。进程之间要约定一个键值
进程A ->创建共享内存->加载共享内存->卸载共享内存->销毁共享内存
进程B -> 加载共享内存->卸载共享内存

  • 1.创建共享内存
 #include <sys/ipc.h> 
 #include <sys/shm.h>
  int shmget(key_t key, size_t size, int shmflg);

key:key值
size:共享内存的大小,尽量是4096的倍数,如果引用一个已存在的共享内存,则指定为0
shmflg:IPC_CREATIPC_EXCL
st_mode mode 权限
返回值:IPC对象标识符

  • 2.加载共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:shmget()的返回值
shmaddr:进程提供的虚拟地址,如果为NULL,操作系统会自动选择一块地址映射
shmflg:
SHM_RND:当shmaddr为空时自动分配
SHM_RDONLY:限制内存的权限为只读
SHM_REMAP:映射已经存在的共享内存
返回值:映射后的虚拟内存地址(进程的虚拟地址与共享的内存映射)

  • 3.卸载共享内存
int shmdt(const void *shmaddr);

返回值:成功为0,失败为-1
进程的虚拟地址与共享的内存取消映射关系

  • 4.控制/销毁共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

cmd:
IPC_STAT:获取共享内存的属性
IPC_SET:设置共享内存的属性
IPC_RMID:删除共享内存
IPC_INFO:获取共享内存的信息(special Linux)
buf:记录共享内存属性的对象

消息队列
  • 消息队列是一个由系统内核负责存储和管理、并通过IPC对象标识符获取的数据链表
  • 1.创建或获取消息队列
#include <sys/types.h>  
#include <sys/ipc.h> 
#include <sys/msg.h>
int msgget(key_t key, int msgflg);

msgflg:创建:IPC_CREAT|IPC_EXEC
获取:0
返回值:IPC对象标识符

  • 2.发送一条消息到消息队列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid:msgget的返回值
msgp:消息(消息类型+消息内容)的首地址
msgsz:消息内存的长度(不包括消息类型)
msgflg

  • 3.从消息队列接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

msqid:msgget的返回值
msgp:接收消息的缓冲区地址
msgsz:要接受的消息长度
msgtyp:消息类型(包含在消息的前4个字节)
msgflg:

MSG_NOWAIT:如果要接的消息不存在,则直接返回。(若不加则会阻塞等待)
MSG_NOERROR:当消息的实际长比msgsz(要接受的信号长度)还要长的话,则按照msgsz长度截取(若不加则会出错)
MSG_EXCEPT:从消息队列中接收第一个不是msgtyp类型的消息

  • 4.控制/销毁消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

cmd
IPC_STAT:获取消息队列属性
IPC_SET:设置消息队列属性
IPC_RMID:删除消息队列

信号量
  • 信号量(信号灯),可以当做进程与进程之间共享的全局变量,一般用来为共享的资源计数

信号量的使用方法
进程A:创建信号量,并设置初始值(设置资源的数)
进程B:获取信号量,查看信号量(查询剩余资源的数量),减少信号量(使用资源),增加信号量(资源使用完毕,归还)

  • 当一个进程尝试减少信号量,如果不能减(代表资源使用完毕),则进程会进入等待状态(休眠),当信号量能够被减时(其他进程归还资源),进程会被唤醒
  • 信号量编程模式
  • 1.创建信号量或获取信号量
 #include <sys/types.h>  
 #include <sys/ipc.h>  
 #include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);

nsems:信号量的数量
semflg:IPC_CREAT|IPC_EXEC|0644
返回值:成功返回信号量标识符,失败返回-1

  • 2.增加或减少信号量
int semop(int semid, struct sembuf *sops, unsigned nsops);

semid:信号量标识符,semget的返回值
struct sembuf{}
unsigned short sem_num; 信号量的编号
short sem_op; 对信号量的操作
(1)若sem_op为正,这对应于进程释放占用的资源数。sem_op值加到信号量的值上。(V操作)
(2)若sem_op为负,这表示要获取该信号量控制的资源数。信号量值减去sem_op的绝对值。(P操作)
(3)若sem_op为0,这表示调用进程希望等待到该信号量值变成0
short sem_flg; 操作权限 :IPC_NOWAIT 要接的消息不存在,直接返回(不阻塞)
nsops:sops数组中元素个数

  • 3.控制/操作信号量
int semctl(int semid, int semnum, int cmd, ...);

semnum:信号量的编号
cmd
IPC_STAT 读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
IPC_SET 设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID 将信号量集从内存中删除。
IPC_INFO 获取信号量的属性
GETALL 用于读取信号量集中的所有信号量的值。
GETNCNT 返回正在等待资源的进程数目。
GETPID 返回最后一个执行semop操作的进程的PID。
GETVAL 返回信号量集中的一个单个的信号量的值。
GETZCNT 返回这在等待完全空闲的资源的进程数目。
SETALL 设置信号量集中的所有的信号量的值。
SETVAL 设置信号量集中的一个单独的信号量的值。

IPC相关命令
  ipcs -m 查看共享内存
  ipcrm -m id 删除共享内存
  ipcs -q 查看消息队列
  ipcrm -q id 删除消息队列
  ipcs -s 查看信号量
  ipcrm -s id 删除信号量

四、网络进程间通信方式

 就是不同机器的进程间通信方式,socket套接字。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值