进程间通信

14 篇文章 0 订阅
4 篇文章 0 订阅

一、基本概念

什么叫进程间通信(IPC,Interprocess communication):
是指两个或多个进程之间交换数据的过程叫进程间通信

进程间为什么需要通信:
当需要多个进程协同工作高效率完成任务时,每个进程都是是独立的个体(资源单位),进程间就需要进行通信。
进程间通信方式的分类:
1、简单的进程间通信:命令行参数、环境变量表、信号、文件
2、传统进程通信:管道
3、XSI进程间通信:共享内存、消息队列、信号量
4、网络进程间通信:socket

二、传统的进程通信——管道

管道是UNIX系统最古老的进程间通信方式(基本不再使用),历史上的管道通常是半双工(只允许单向数据流动),现在的系统大都可以全双工,数据可以双向流动。

1、有名管道(创建实体文件)
	命令:mkfifo
	函数:mkfifo
	int mkfifo(const char *pathname, mode_t mode);
	功能:创建管道文件
	pathname:文件路径
	mode:权限
	返回值:成功返回0,失败返回-1
	
	编程模型:
		进程A:							进程B:
			创建管道(mkfifo)				...
			打开管道(open)					打开管道
			读/写数据	(read/write)			读/写数据
			关闭管道(close)					关闭管道
			删除管道	(unlink)				...
	
2、无名管道(用于通过fork创建的父子进程的通信)
	int pipe(int pipefd[2]);
	功能:创建无名管道
	pipefd:用来储存内核返回的文件描述符
		pipefd[0] 用于读操作
		pipefd[1] 用于写操作

三、XSI进程间通信

X/open组织为UNIX系统设计的一套进程间通信机制,有共享内存、消息队列、信号量。
1、IPC标识
内核会为每个XSI的进程间通信维护一个IPC对象(XSI对象)
该对象通过一个非负整数来引用(类似于文件描述符)
与文件描述符不同的是,每用一个IPC对象标识符就持续+1,达到最大值时再从0开始
IPC标识需要程序员自己创建(类似于创建文件)
2、IPC键值
创建IPC键值的依据(类似创建文件的文件名),也是一个非负整数。
1、自定义(不建议,可能会冲突)
2、自动生成(项目路径,项目编号)
key_t ftok(const char *pathname, int proj_id);
注意:项目路径一定要是有效路径,生成IPC键值依靠的是路径而不是字符串
3、IPC对象的创建
IPC_PRIVATE 创建IPC对象时永远创建成功
IPC_CREAT 对象存在则获取,不存在则创建
IPC_EXCL 如果对象已经存在,则创建失败
4、IPC对象销毁/控制用到的宏
IPC_STAT 获取IPC对象的属性
IPC_SET 设置IPC对象的属性
IPC_RMID 删除IPC对象

四、共享内存

共享内存就是在内核中开辟一块内存由IPC对象管理内存,进程A通和进程B都用自己的虚拟地址与它的进程映射,这样他就共享了同一块内存,然后就可以通信了。
特点:
	1、不需要复制信息,是最快的一种进程间通信机制
	2、需要考虑同步问题(必须借助其他的机制,如信号)
编程模型:		
	进程A						进程B
	生成IPC键值	ftok			生成IPC键    ftok	
	创建共享内存	shmget			获取共享内存    shmget
	映射共享内存	shmat			映射共享内存	  shmat
	使用共享内存	*ptr			使用共享内存	  *ptr
	取消映射共享内存	shmdt		取消映射        shmdt
	删除共享内存	shmctl			...
	
	int shmget(key_t key, size_t size, int shmflg);
	功能:创建/获取共享内存
	key:IPC键,由ftok函数生成
	size:共享内存的大小,最好是4096的整数倍,获取共享内存时,此值无效
	shmflg:
		0 获取共享内存
		IPC_CREAT 创建
		IPC_EXCL  如果存在则创建失败
		返回值:成功返回共享内存标识(IPC标识),失败返回-1
		
	void *shmat(int shmid, const void *shmaddr, int shmflg);
	功能:映射共享内存
	shmid:共享内存标识符,shmget函数的返回值
	shmaddr:进程提供的虚拟地址,与内核中的内存映射用的,也可以是NULL(内核会自动选择一个地址映射)
	shmflg:
		0  自动分配
		SHM_RDONLY 只读权限
		SHM_RND  当shmaddr不空时shmaddr向下取整页
	返回值:映射成功后的虚拟地址。
	
	int shmdt(const void *shmaddr);
	功能:取消虚拟地址与共享内存的映射
	shmaddr:被映射过的虚拟地址
	
	int shmctl(int shmid,int cmd,struct shmid_ds* buf)
	功能:删除共享内存,获取/设置共享内存的属性
	shmid:共享内存标识符
	cmd:
		IPC_STAT  获取共享内存的属性
		IPC_SET	  设置共享内存的属性
		IPC_RMID  删除IPC共享内存
		
	struct shmid_ds {
           struct ipc_perm shm_perm;    //内存所有者及权限
           size_t          shm_segsz;   //内存的大小
           time_t          shm_atime;   //最后的映射时间
           time_t          shm_dtime;   //最后的取消映射时间
           time_t          shm_ctime;   //最后的修改时间
           pid_t           shm_cpid;    //创建者进程ID
           pid_t           shm_lpid;    //最后映射/取消映射的进程ID
           shmatt_t        shm_nattch;  //映射的次数
           ...
       };
		struct ipc_perm {
           key_t          __key;    // 创建IPC的键值
           uid_t          uid;      // 有效用户ID 
           gid_t          gid;      // 有效组ID
           uid_t          cuid;     // 创建者的用户ID
           gid_t          cgid;     // 创建者的组ID
           unsigned short mode;     // 权限
           unsigned short __seq;    // IPC标识
       };

五、消息队列

消息队列就是由内核管理的一个管道,可以按顺序发送消息包(消息类型+消息内容),可以全双工工作。
可以不按消息的顺序接收消息

int msgget(key_t key, int msgflg);
功能:创建/获取消息队列
key:IPC键值,由ftok函数自动生成
msgflg:
 	0 获取消息队列
 	IPC_CREAT 	创建消息队列
	IPC_EXCL	如果存在则创建失败
	返回值:消息队列标识

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列发送消息
key:IPC键值,由ftok函数自动生成
msgflg:消息队标识,msgget函数的返回值	 
msgp:结构指针
	struct msgbuf {
           long mtype;       //消息类型
           char mtext[n];    //消息内容
       };
 msgsz:消息的长度,不包括消息类型,sizeof(msgbuf)-4
 msgflg
 	0 阻塞,当消息队列满时,等待
 	1 不阻塞,当消息队列满时,不等待

返回值:成功发送返回0,失败发送返回-1

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列中按类型获取消息
msqid:消息队列标识,msgget函数的返回值
msgp:
	struct msgbuf {
           	long mtype;       //消息类型
           	char mtext[n];    //消息内容
       			};
   msgsz:要接收的消息长度,可以长一点
   msgtyp:要接收的消息类型
   		0 接收任意类型的消息(接收队列中第一个消息)
   		>0	只接收msgtyp类型的消息
   		<0 	接收消息队列中小于等于msgtyp绝对值的消息,取小的那个
   msgflg:
   		0	阻塞,当消息队列中是否由对应的消息队列,等待
		1   不阻塞,消息队列中没有对应类型的消息,则返回
		MSG_NOERROR:
			消息类型正确,而消息的实际长度大于msgsz,则不接收消息并返回-1
			如果msgflg带MSG_NOERROR标识,则把多余的消息截取,成功接收
		IPC_NOWAIT:如果消息队列没有要接收类型的消息,则不等待,返回-1
		MSG_EXCEPT:接收消息队列中第一个消息类型不是msgtyp的消息,编译时添加参数-D_GNU_SOURCE。
		
	返回值:成功接受的字节数	
	
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:删除消息队列,设置或获取消息队列
msqid:消息队列标识,msgget函数的返回值
cmd:
		IPC_STAT  获取共享内存的属性
		IPC_SET	  设置共享内存的属性
		IPC_RMID  删除IPC共享内存
返回值:成功返回0,失败返回-1。
	
	 struct msqid_ds {
           struct ipc_perm msg_perm; 	 //权限
           time_t          msg_stime;    //最后一个消息发送时间
           time_t          msg_rtime;    //最后一次消息接收时间
           time_t          msg_ctime;    //最后一次修改时间
           unsigned long   __msg_cbytes; //消息队列中的字节数
           msgqnum_t       msg_qnum;     //消息的个数
           msglen_t        msg_qbytes;   //消息队列中容纳的最大字节数
           pid_t           msg_lspid;    //最后一次发送消息的进程
           pid_t           msg_lrpid;    //最后一次接收消息的进程
       };

六、信号量

内核维护的计数器,用于管理多进程之间共享资源。
例如:有个变量n表示资源的数量,当有进程想要独占一个资源时,n的值要-1(可能减多个),如果n的值等于0(不够减),则进程停止下来(进程阻塞),直到n的值可以减,当资源使用完毕后n的值要加1(可能加多个)。

int semget(key_t key, int nsems, int semflg);
功能:创建/获取信号量
key:IPC键值
nsems:信号量的数量
semflg:
	0 获取信号量
	IPC_CREAT 创建信号量(已存在则获取,不存在则创建)
	IPC_EXCL  如果已存在则创建失败
	返回值:信号量标识
	
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:操作信号量(对信号进行加/减操作)
semid:信号量标识符,semget的返回值
sops:结构体数组
nsops:数组的长度
struct sembuf{
	   unsigned short sem_num;  //信号量的下标
       short          sem_op;   //操作
       short          sem_flg;  //标记
       		IPC_NOWAIT		当信号量不够减时,不阻塞
       		SEM_UNDO		当进程结束时,信号量的自动归还
		
		struct timespec
			_time_t tv_sec;
			long int tv_
			
			}
int semtimedop(int semid, struct sembuf *sops, unsigned nsops,struct timespec *timeout);
功能:带时间限制的操作信号量

int semctl(int semid, int semnum, int cmd, ...);
功能:初始化信号量的值,删除信号量,获取设置信号量的属性	
cmd
	IPC_STAT 获取信号量的属性
	IPC_SET	 设置信号量的属性
	IPC_RMID 删除信号量
	IPC_INFO 获取信号量的信息
	SEM_INFO 设置信号量的信息
	GETALL   获取所有信号量的值
	GETNCNT  获取信号量的数量
	
	
编程模型:
进程A							进程B
创建信号量	semget				获取信号量
初始化信号量的值	semctl			...
加减信号量	semop				加减信号量
销毁信号量	semctl				...

注意:信号量是用来计数的,一定要与资源对应

七、IPC命令

显示IPC对象
ipcs -m
ipcs -q
ipcs -s
ipcs -a

删除IPC对象
ipcrm -m ID
ipcrm -q ID
ipcrm -s ID

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值