笔记五:进程间的通信(IPC通信之共享内存)

IPC通信

IPC通信(Inter-Process Communication)

三种: 共享内存、消息队列、信号灯

这个IPC对象,肯定是存在于内核中。而且用户空间的文件系统中有没有IPC的文件类型?没有

有名管道为什么能实现无亲缘关系的进程之间的通信?

是因为用户空间有管道这种文件类型。 

IPC是不是只能用于亲缘关系进程之间的通信呢?肯定不是

它是怎样实现无亲缘关系之间的通信呢?也即你是保证用户空间的二个进程对内核中的同一个IPC对象的操作。(ftok

IPC对象的打开或创建:  类似于open的函数呢?                                           
IPC和文件I/O函数的比较
文件I/O
IPC
open
Msg_get              
S hm_get
S em_get
read
write
msgsnd msgrecv
shmat shmdt
semop
close
msgctrl
shmctrl
semctrl
  
1.共享内存 
(1) shmget
 
所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型
int shmget(key_t key, int size, int shmflg);
函数参数
key IPC_PRIVATE ftok 的返回值
 
size :共享内存区大小
 
shmflg :同 open 函数的权限位,也可以用 8 进制表示法
函数返回值
成功:共享内存段标识符---ID---文件描述符
  
函数返回值
成功:共享内存段标识符---ID---文件描述符
 
出错: -1
  
查看IPC对象    ipcs –m:查看共享内存           ipcs  -q:查看消息队列   ipcs -s:查看信号
删除IPC对象    ipcrm  -m  id
返回值:共享内存段标识符  IPC的ID号
通过宏定义IPC_PRIVATE创建共享内存,那么ID号都为0
打开或创建一个共享内存对象,共享内核在内核是什么样子的?
一块缓存,变类似于用户空间的数组或malloc函数分配的空间一样
memcpy(p,"abcd",4);(字符串拷贝)
第一个参数:共享内存中;
第二个参数:字符串;
第三个参数:size(大小);
(2) ftok:创建key值。
函数原型:    char  ftok(const char *path, char key )
参数:           第一个参数:文件路径和文件名;
第二个参数:  一个字符。
返回值:        正确返回一个key值,出错返回-1 
IPC_PRIVATE操作时,共享内存的key值都一样,都是0,所以使用ftok来创建key值。只要key值是一样的,用户空间的进程通过这个函数打开,则会对内核的同一个IPC对象操作。
例子:
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include "stdlib.h"
#include "stdio.h"
int main(int argc,char *argv[])
{
  int key;
  int shmid;
  char *p;//
  key=ftok("./a.c",'b');
  if(key  <0 )
  {
      printf("creat key failure\n");
      return -1;
  }
  shmid= shmget(key,128,IPC_CREAT | 0777);
  if(shmid < 0)
  {
      printf("creat share memory failure\n");
      return -2;
  }
  return 0;
}
(3) shmat  将共享内存映射到用户空间的地址中
能不能用read ,write呢?(必须每次进入内核调用)
为了方便用户空间对共享内存的操作,使用地址映射的方式。
函数原型:void *shmat (int shmid, const void *shmaddr, int shmflg);   //malloc(通过这个函数就会映射到用户空间,所以就更加方便了没有必要每次进入内核进行操作)
参数:      第一个参数:ID号;
                第二个参数:映射到的地址,NULL为系统自动完成的映射;
                第三个参数shmflg:    SHM_RDONLY共享内存只读         默认是0,表示共享内存可读写。
返回值:   成功:映射后的地址;   失败:NULL。
共享内存特点:
共享内存创建之后,一直存在于内核中,直到被删除或系统关闭;
共享内存和管道不一样,读取后,内容仍在其共享内存中。
(4) shmdt:将进程里的地址映射删除
函数原型:int shmdt(const void *shmaddr);
参数:      shmaddr共享内存映射后的地址
返回值:   成功:0    出错:-1
(5)  shmctl:删除共享内存对象
函数原型:int shmctl(int shmid,  int cmd,  struct shmid_ds  *buf);
函数参数:第一个参数shmid:要操作的共享内存标识符。
                第二个参数cmd:IPC_STAT  (获取对象属性)---  实现了命令ipcs -m
                                          IPC_SET (设置对象属性)
                                          IPC_RMID (删除对象)   ---实现了命令ipcrm -m(删除的时候第三个参数可以设置为NULL);
                第三个参数buf :指定IPC_STAT/IPC_SET时用以保存/设置属性。(进行设置的时候)
函数返回值:成功:0          出错:-1
有亲缘关系进程之间的通信的实例:
1.怎样通过共享内存实现有亲缘关系进程之间的通信框架
当使用IPC_PRIVATE 实现有亲缘关系进程之间通信时,fork()函数一定要放在shmget()函数之后
例子:(单向通信一个写端一个读端)
read.c端
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include "stdlib.h"
#include "stdio.h"
int main(int argc,char *argv[])
{
  int key;
  int shmid;
  char *p;//
  key=ftok("./a.c",'b');//通过ftok创建key值,实现非亲缘关系进程间的通信;
  if(key  <0 )
  {
      printf("creat key failure\n");
      return -1;
  }
  shmid= shmget(key,128,IPC_CREAT | 0777);//创建共享内存
  if(shmid < 0)
  {
      printf("creat share memory failure\n");
      return -2;
  }
  p=(char *)shmat(shmid,NULL,0);//将内存映射到用户空间
  if(p == NULL)
  {
      printf("shmat failure\n");
      return -3;
  }
   /*从共享内存中读*/
  while(1)
  {
      sleep(2);
    printf("recv from share memory data : %s\n",p);
  }
  shmdt((void *)p);//将进程里的地址映射删除;
  p=NULL;
  //shmctl(shmid,IPC_RMID,NULL);//将内核空间的缓存进行释放,每次用完必须进行释放,否则一直存在于内核中;写端已经删除所以读端可以不用释放;

  return 0;
}
write.c端
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include "stdlib.h"
#include "stdio.h"
int main(int argc,char *argv[])
{
  int key;
  int shmid;
  char *p;//
  key=ftok("./a.c",'b');
  if(key  <0 )
  {
      printf("creat key failure\n");
      return -1;
  }
  shmid= shmget(key,128,IPC_CREAT | 0777);
  if(shmid < 0)
  {
      printf("creat share memory failure\n");
      return -2;
  }
  p=(char *)shmat(shmid,NULL,0);
  if(p == NULL)
  {
      printf("shmat failure\n");
      return -3;
  }
   /*往共享内存中写入*/
  while(1)
  {
      printf("please input send to share memory data:\n");
      fgets(p,128,stdin);
      if(strncmp(p,"quit",4) == 0)
            break;
  }
  shmdt((void *)p);
  p=NULL;
  shmctl(shmid,IPC_RMID,NULL);//将内核空间的缓存进行释放,每次用完必须进行释放,否则一直存在于内核中;

  return 0;
}
posted @ 2017-02-26 16:44  奔涌吧,后浪  阅读(24)  评论(0编辑  收藏  举报