Linux进程通信机制
管道
信号量
消息队列
共享内存
Socket通信
Linux通信机制是指在Linux操作系统中实现进程间通信的方式和技术,主要包括以下几种通信机制:
1. 管道(Pipe):管道是一种半双工的通讯机制,它只能实现具有亲缘关系(如父子进程之间)的进程间通信。
2. 命名管道(FIFO):命名管道是一种特殊文件,可用于多个进程间通信。
3. 信号(Signal):信号是一种比较简单的通信机制,主要用于异步通信,进程间通信通过发送和接收信号来实现。
4. 消息队列(Message Queue):消息队列是一种进程间通信机制,它可以实现不同进程间的通信,通过消息发送和接收实现。
5. 共享内存(Shared Memory):共享内存是一种高效的通信机制,可以实现进程之间的数据共享,通过直接读写内存实现。
6. 信号量(Semaphore):信号量是一种进程间同步机制,可以用来保护共享资源,控制进程的访问。
7. 套接字(Socket):套接字是一种实现网络通信的机制,也可以实现进程间通信,通过网络协议实现进程间通信。
1.管道(先进新出)
实质:由内核管理的一个缓冲区
- 信息输出,数据写入管道
- 信息输入,从管道读取信息
匿名管道:亲缘关系 进程间通信 退出销毁
命名管道: 联系弱 读写内存接口 退出仍存在
匿名管道:
- 创建 pipe()
- 关闭不用端口,close()
- 通信:读写操作,read/write()
- 关闭,close()
-
- 创建 pipe()
#include<unistd.h>
Int pipe(int pipefd[2]);//传入参数,文件描述符数组
父进程读,子进程写
pipe()创建管道后读端的文件描述符为fd[0],写端的文件描述符为fd[1];
dup2();
#include <unistd.h>
Int dup2(int oldfd,int newfd);
文件参数是要执行的可执行文件的路径名
【管道通信】:popen/pclose函数
#include <stdio.h>
FILE *popen(const char *command,const char *type);
Int pclose(FILE *stream);
Popen():
- 调用pipe()à创建管道
- 调用fork() à创建子进程
- 子进程:通过execve()调用shell
Pclose()
-
- 关闭popen()打开的I/O流
- 调用wait()等待子进程命令执行结束
- 返回shell的终止状态,防止僵尸进程
2.命名管道
#include <sys/type.h>
#include <sys/stat.h>
Int mkfifo(const char *pathname,mode_t mode)
创建命名管道(FIFO文件) 文件形式存在 路径名->文件
FIFO文件和普通文件的区别:
Fifo 文件 对内存操作 读写快 可以通过普通文件
普通文件 在硬盘 读写慢
3.消息队列:管道改进版
本质:存放消息链表 内核 标识符:(队列key)
通信机制:传递的数据有结构 不是简单字节流
写数据==数据结构(插入结点)
读数据==数据结构(删除结点)
管道和消息队列的共同不足:每个数据块的最大长度有限,系统上
全体队列的最大长度也有限
消息队列进程通信:
- 创建消息队列
- 发送消息->消息队列
- 消息队列->读取
- 删除消息队列
用户消息缓冲区
通过msgtype区分数据类型
Int msgget(key,IPC_CREAT|IPC_EXCL|0664);
表示:
若不存在,自动创建
若存在,返回(EEXIST),无需创建(创建并打开消息队列)
已存在,打开
如:
Int msgget(key,0664);
Msgget()://创建消息队列/获取已经存在的消息队列
#include <sys/msg.h>
Int mssget(key_t key ,int msgflg);
Msgsnd()://发送消息
#include <sys/msg.h>
Int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg);
Msgrcv()://接收消息
#include <sys/msg.h>
Ssize_t msgcrv(int msqid, void *msgp,size_msgsz,long msgtyp,int msgflg);
Msgctl()://控制,删除,获取属性
#include <sys/ipc.h>
Int msg
Msgctl(int msqid,in cmd,struct msqid_ds *buf);
键值ID:msgget函数的返回值 >=0 内部名->进程级别的唯一标识
不支持进程间通信
标识符(key):实现消息队列和进程的关联 外部名->内存级别的唯一标识
多个进程——>同一个key调用msgget ->标识同一个进程间通信的结构
4.信号量
作用:解决进程同步与互斥的通信机制
区别:不同于管道,FIFO,消息队列,不用来传输数据
包括:
资源数量:>=0变量
修改信号量:原子操作p,v
该信号下:等待资源的进程队列
步骤:
- 创建信号量/集 获取已有的
- 初始化信号量、信号量集
- P,V操作:(1)修改信号量数量
(2)P:-1
(3)V:+1
④删除不需要的信号量
Linux内核三个系统调用:
Semget()//创建新的信号量、集 获取已经存在的
#include <sys/sem.h>
Int semget(key_t key(键值,传入参数),int nsems(信号量数目),int semflg(设置权限));
Semctl()//信号量控制 (初始化,删除)
#include <sys/sem.h>
Int semctl(int semid(信号量标识符,semgget返回值),int semnum(编号),int cmd(SETVAL—初始化,IPC-RMID-删除)
Semop()//改变信号量的值
#include <sys/sem.h>
Int semop(int semid(信号量标识符),struct sembuf *sops(struct sembuf 的数组指针),unsigned nsops(sops所指的元素个数));
共享内存(效率最高)
允许>=2的进程访问同一个存储区域、
共享内存与信号量一起,信号量:读写操作同步
- 获得一块共享内存段
- 创建的共享内存段->映射->不同进程空间(可断开)
- 不需要访问时,断开映射
- 不需要时,释放共享内存段
Linux系统调用:
Shmget()//创建共享内存段,打开已有的
#include <sys/shm.h>
Int shmget(key_t key(传入参数,键值),size_t size共享内存大小),int shmflg(shmget创建条件,权限));
Shmat()//地址映射
#include <sys/shm.h>
Void shmat(int shmid(共享内存标识,shmget返回值),const void *shmaddr(指针类型的传入参数,映射地址),int shmflg(使用方式));
Shmdt()//解除物理内存与进程虚拟地址空间的映射关系
#include <sys/shm.h>
Int shmdt(const void *shmaddr(shmat返回的虚拟空间地址));
Shmctl()//已存在的操作
#include <sys/shm.h>
Int shmctl(int shmid(共享内存标识符),int cmdS(IPC-STAT 属性保存在3 IPC-SET 用3设置属性 IPC-RMID 删除 3为null),struct shmid_ds *buf(shmid-ds 的指针));
特殊说明:
共享内存,消息队列,信号量 释放
调用fork()创建子进程,继承父进程联系的共享内存
调用exec()函数更改时,exit函数时, 子进程解除映射 shmctl进行删除