进程间通信的几种方法

一、基本概念
进程间通信:
Inter-Process Communication,简称IPC,指的是两个以上的进程之间进行数据交换的过程。

进程之间为什么需要通信:当解决一个庞大复杂的问题时需要多进程合作完成,而进程之间是相互独立的(fork创建出的进程子进程拷贝父进程,vfork是子进程替换父进程),进程之间想要协同配合就需要进行通信。

进程间通信技术的分类:
简单的进程间通信:
命令行参数、环境变量:通过vfork创建子进程时可以附加一些参数和环境变量。
信号:只能传递简单的数据
文件:不能同步、不及时、可能有错漏。
传统的进程间通信:管道技术,但速度较慢,同一时刻只能单向传递。
XSI进程间通信:X/Open System Interface
共享内存、消息队列、信号量
网络进程间通信:
本地套接字、网络套接字

二、管道通信
管道是UNIX系统最古老的一种进程间通信方式,历史上的管道是半双工(只能单向传递数据),现在的基本上都是全双工(可以双向通信,但同一时刻只能一方传递另一方接收)。
有名管道:基本文件名(管道文件)的通信。
创建管道文件:
命令:mkfifo 文件
函数:int mkfifo(const char *pathname, mode_t mode);
功能:创建管道文件
pathname:路径
mode:权限
返回值:成功返回0,失败返回-1。

	编程模型
	进程A			进程B
	创建管道文件	
	打开管道文件		打开管道文件
	写入数据			读取数据
	关闭管道			关闭管道
	删除管道	

如果A写完数据等着接收B的数据,但在B把数据接收到之间,A就可能已经把数据拿走了,B就读不到了,因此要想实现双向通信需要两个管道文件。

匿名管道:调用系统api,系统会自己创建一个管道,并返回两个文件描述符。
	int pipe(int pipefd[2]);
	功能:获取两个管道文件的文件描述符。
	注意:只能fork创建进行父子进程间的通信。
		pipefd[0]:读取数据
		pipefd[1]:写入数据

三、XSI进程间通信
1、IPC标识
1)、内核会为每个进程间通信维护一个结构体形式的IPC对象。
2)、每一个IPC对象通过一个非负整数(IPC标识)来引用。
3)、与文件描述符不同的是,IPC标识在使用时持续加1,达到最大值时就变成0。
2、IPC键值
1)、IPC键值是创建IPC对象时提供的凭证(类似创建文件时所提供的文件名)。
2)、两个进程之间如果都提供同一个IPC键值就能获取同一个IPC对象。
3)、无论什么时候,创建、获取IPC对象都必须提供IPC键值。
4)、IPC键值的类型是 unsigned int 定义在sys/types.h文件中,key_t。
5)、创建、获取IPC对象时,不建议填写,一般使用函数计算。
key_t ftok(const char *pathname, int proj_id);
功能:让系统计算出一个独立无二的IPC键值
pathname:项目路径
proj_id:项目编号,取值范围 0~255
注意:计算键值依靠的不是字符本身,而是路径。

四、XSI进程间通信之共享内存
1、基本特点
1)、多个进程之间共享一块由于系统负责维护的内存区域,这堆内存可以映射到进程的堆地址、栈地址。
2)、不需要复制数据,就可以通信,因此它是一种最快的进程间通信方式。
3)、缺点是需要解决同步问题,需要其它技术配合。
2、操作函数
int shmget(key_t key, size_t size, int shmflg);
功能:创建/获取一块共享内存
key:IPC键
size:共享内存的大小
shmflg:
IPC_CREAT:创建共享内存,不存在就创建
IPC_EXCL:存在就不创建,并出错
返回值:IPC标识

	void *shmat(int shmid, const void *shmaddr, int shmflg);
	功能:映射共享内存
	shmid:共享内存对象的IPC标识
	shmaddr:进程提供的映射地址
	shmflg:
		0 以读写权限映射
		SHM_RND 当shmaddr为NULL时,系统自动分配映射地址。
		SHM_RDONLY 以只读权限映射。
	返回值:映射成功后的地址。
	
	int shmdt(const void *shmaddr);
	功能:取消共享内存映射
	shmaddr:映射过的共享内存首地址
	
	int shmctl(int shmid, int cmd, struct shmid_ds *buf);
	功能:控制共享内存,常用于销毁。
	shmid:共享内存对象的IPC标识
	cmd:
		IPC_STAT:获取共享内存属性
		IPC_SET:设置共享内存属性
		IPC_RMID:删除共享内存
	buf:共享内存属性结构体

3、编程模型:
进程A 进程B
创建共享内存 获取共享内存
映射 映射
取消映射 取消映射
删除

四、XSI进程间通信之消息队列
1、基本特点
1)、消息队列是由内核维护的一个双向链表,负责存储和管理进程间通信的数据。
2)、消息队列发送的数据可以排队、消息长度不固定、并且可以按类型发送、接收消息。
2、操作函数
int msgget(key_t key, int msgflg);
功能:创建/获取消息队列
key:IPC键值
msgflg:
IPC_CREAT:不存在就创建,存在就获取。
IPC_EXCL:如果存在,就出错返回负1。
返回值:消息队列IPC标识。

	int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
	功能:向消息队列发送数据
	msqid:消息队列IPC标识,msgget的返回值
	msgp:要发送的数据的首地址
		struct msgbuf {
           long mtype;       /* message type, must be > 0 */
           char mtext[1];    /* message data */
        };
	msgsz:消息长度,不包括类型
	msgflg:
		0:当消息发送成功时才返回。
		IPC_NOWAIT:当消息队列满时,不等待。
	返回值:成功返回0,失败返回-1。

   ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
   功能:从消息队列接收数据
   msqid:消息队列IPC标识,msgget的返回值
   msgp:要数据存放的缓冲区首地址
   msgsz:缓冲区的大小
   msgtyp:消息类型
   msgflg:
   		0:消息不存在时等待,直到接收成功为止。
   		IPC_NOWAI:消息不存在时,不等待,立即返回。
   		
   int msgctl(int msqid, int cmd, struct msqid_ds *buf)
   功能:控制/销毁消息队列
   功能:从消息队列接收数据
   cmd:
   		IPC_RMID 删除消息队列
   		IPC_STAT 获取消息队列属性
   		IPC_SET 设置消息队列属性
   buf:消息队列属性结构体

3、编程模型
进程A 进程B
创建消息队列 获取消息队列
向消息队列发送数据 从消息队列获取数据
从消息队列获取数据 向消息队列发送数据
销毁消息队列

四、XSI进程间通信之信号量
1、基本特点:内核维护一个整型变量,用于限制多个进程对有限资源的访问。
2、多个进程获取有限资源的操作方式:
1)测试控制该资源的信号量(整型变量)。
2)如果信号量的值大于0,表示该资源还可以获取,将信号进行减1操作。
3)如果信号量的值等于0,表示该资源已经耗尽,进程自动进入休眠,直到信号量大于0,进程则被唤醒。
4)当进程使用完资源时则对信号时执行加1操作,而等待信号量的其它进程将被唤醒。

2、常用函数
	int semget(key_t key, int nsems, int semflg);
	功能:创建/获取信号量
	key:IPC键值
	nsems:创建信号量的数量(类似数组的长度)。
	semflg:
		IPC_CREAT 创建/获取信号量
		IPC_EXCL 如果信号量存在则出错
		mode 权限
	返回值:信号量标识
	
	int semop(int semid, struct sembuf *sops, unsigned nsops);
	功能:操作信号量,对信号量执行加n或减n操作
	semid:信号量标识,semget的返回值
	sops:信号量操作结构体
		unsigned short sem_num; 信号量的下标
        short          sem_op; 对信号时的操作
        short          sem_flg; 对信号量操作是否等待
        	SEM_UNDO 等待
        	IPC_NOWAIT 不等待
    nsops:如果值是0,则对单个的信号进行操作,非零则对所有信号量集体操作。
    
   int semtimedop(int semid, struct sembuf *sops, unsigned nsops,struct timespec *timeout);
   功能:有倒计时的对信号时进行操作,如果时间到了还不能对信号量进行操作,则立即返回。
   timeout:时间结构体
	__time_t tv_sec;	等待的秒数
	long int tv_nsec;	等待的纳秒数
   
   int semctl(int semid, int semnum, int cmd, ...);
   功能:对信号量进行操作(销毁、设置属性、获取属性、初始化信号量、获取信号量的值)
   semnum:信号时的编号(下标)
   cmd:
   	IPC_STAT 获取信号量的属性
   	IPC_SET 设置信号量的属性
   	IPC_RMID 删除信号量
   	SEM_INFO 获取信号时的信息
   	SET_STAT 获取某个信号量的属性
   	GETALL 获取所有信号量的值
   	GETNCNT 获取信号量的数量
   	GETVAL 获取某个信号量的值
   	SETVAL 设置某个信号量的值
   	SETALL 设置所有信号量的值

3、编程模型
进程A 进程B
创建信号量 获取信号量
初始化信号量的值 获取信号量的值
-1 获取资源 -1 如果不能减则阻塞
… …
+1 归还资源 +1 归还资源
销毁信号量

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值