进程间的通信IPC-共享内存

1 篇文章 0 订阅
1 篇文章 0 订阅

进程间通信IPC-共享内存涉及的函数

1.获取进程间通信的唯一标识(系统建立IPC通信 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到)
函数原型key_t ftok( const char * fname, int id );
函数功能:获取进程间通信的唯一标识(系统建立IPC通信 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到)
头文件:#include <sys/types.h> #include <sys/ipc.h>
函数参数
参数1:指定的文件名(必须是已经存在的,一般试用当前目录 )
参数2:id是子序号。根据自己的约定,随意设置;虽然是int类型,但是只使用8bits(1-255)
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。
返回值: 成功:返回key_t值(即IPC 键值)
出错:-1,错误原因存于errno中 (可以使用perror(“信息”);会接着打印errrno对应的错误信息)

2.得到一个共享内存标识符或创建一个共享内存对象
函数原型int shmget(key_t key, size_t size, int shmflg);
函数功能:得到一个共享内存标识符或创建一个共享内存对象
头文件:#include <sys/ipc.h> #include <sys/shm.h>
函数参数
参数1:0(IPC_PRIVATE):会建立新共享内存对象
大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值
参数2:大于0的整数:新建的共享内存大小,以字节为单位
0:只获取共享内存时指定为0
参数3:0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限 (一般为600|IPC_CREAT|IPC_EXCL)
返回值:成功:返回共享内存的标识符
出错:-1,错误原因存于errno中

附加信息
如果用shmget创建了一个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:
shm_lpid、shm_nattach、shm_atime、shm_dtime设置为0。
msg_ctime设置为当前时间。
shm_segsz设成创建共享内存的大小。
shmflg的读写权限放在shm_perm.mode中。
shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。

3.连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
函数原型void *shmat(int shmid, const void *shmaddr, int shmflg)
函数功能:连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
头文件:#include <sys/types.h> #include <sys/shm.h>
函数参数
参数1:shmid共享内存标识符,由shmget()来获取
参数2:指定共享内存出现在本进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
参数3:HM_RDONLY:为只读模式,其他为读写模式(0-读写模式)
注意:当为只读模式时,对返回地址进行写操作(memcpy等)会报段错误,值得小心
返回值:成功:附加好的共享内存地址(该地址是已经映射到本进程的地址,可对该地址进行访问)
出错:-1,错误原因存于errno中

4.断开与共享内存附加点的地址,禁止本进程访问此片共享内存(不是销毁共享内存)
函数原型int shmdt( const void *shmaddr );
函数功能:与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存;本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程
头文件:#include <sys/types.h> #include <sys/shm.h>
函数参数
参数1:shmaddr:连接的共享内存的起始地址
返回值:成功:附加好的共享内存地址(该地址是已经映射到本进程的地址,可对该地址进行访问)
出错:-1,错误原因存于errno中

5.完成对共享内存的控制
函数原型int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函数功能:完成对共享内存的控制,可以得到共享内存的状态、改变共享内存的状态、删除这片共享内存
函数参数
参数1:shmid共享内存标识符,由shmget()来获取
参数2:共享内存操作符
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存(删除共享内存时,第三个参数为NULL)
参数3:共享内存管理结构体buf
返回值:成功:0
出错:-1,错误原因存于errno中
错误代码
EACCES:参数cmd为IPC_STAT,却无权限读取该共享内存
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为shmid的共享内存已被删除
EINVAL:无效的参数cmd或shmid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

进程间的通信实现基本步骤:

服务端:(创建共享内存,向共享内存写入数据)
1.首先使用ftok()来获取一个IPC通信的唯一标识key
2.然后根据这个唯一标识key,使用shmget()来创建一个共享内存区,返回该共享内存shmid (创建时,参数3使用:0600|IPC_CREAT|IPC_EXCL)
3.根据shmid,使用shmat()链接该共享内存,返回映射到本进程的内存地址shmaddr(服务器进行共享内存的数据写入,所以参数3不能是SHM_RDONLY,可以设为0)
4.操作shmat()返回的地址shmaddr,进行数据的写入
5.根据shmaddr,使用shmdt()断开与共享内存的连接

客户端:(获取已创建的共享内存,读取共享内存的数据)
1.首先使用ftok()来获取一个IPC通信的唯一标识key;(参数必须和服务器创建时使用的参数一致,得到的key才一致)
2.然后根据这个唯一标识key,使用shmget()来获取一个共享内存区shmid,返回该共享内存shmid(获取已创建的共享内存shmid时,参数2和3都使用0 )
3.根据shmid,使用shmat()链接该共享内存,返回映射到本进程的内存地址shmaddr (客户端读取共享内存的数据,参数3使用SHM_RDONLY,只读模式)
4.操作shmat()返回的地址shmaddr,进行数据的读取,一般使用memcpy()进行内存的拷贝
5.根据shmaddr,使用shmdt()断开与共享内存的连接

提示信息

1.当服务器需要销毁共享内存时,使用shmctl( shmid, IPC_RMID, NULL);
如果创建完共享内存后,就使用shmctl()进行销毁的话,客户端是读取不到共享内存的,所以一般只在服务器停止时,进行共享内存的销毁。
销毁共享内存时参数1:shmid,一样可以通过ftok()来获取key,然后通过shmget()来得到shmid,然后进行shmct()来进行共享内存的销毁

2.在访问同一共享内存的多个进程先后调用ftok()时间段中,如果fname指向的文件或者目录被删除而且又重新创建,那么文件系统会赋予这个同名文件新的i节点信息,于是这些进程调用的ftok()都能正常返回,但键值key却不一定相同了
所以要确保key值不变,要么确保ftok()的文件不被删除,要么不用ftok(),指定一个固定的key值。

3…共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量。(信号量和共享内存实现同步机制后续再学习再记录)

附加命令

1.查看系统中的共享存储段(linux命令)

ipcs -m

2.删除系统中的共享存储段

ipcrm -m [shmid]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值