天天看点

Linux c 基于内存的进程通信—共享内存、共享队列(消息队列)

基于内存的进程通信:

1.      内核共享内存

编程模型:

    1.1.创建共享内存,得到一个ID  shmget

1.2.把ID影射成虚拟地址(挂载)  shmat

       1.3.使用虚拟地址访问内核共享内存使用任何内存函数与运算符号                        1.4.卸载虚拟地址 shmdt

       1.5.删除共享内存 shctl(修改/获取共享内存的属性)

案例:

A.创建共享内存,并且修改内存数据

1.      创建共享内存

                              #include<sys/shm.h>

                              intshmget(key_t key,//为什么需要key

                                                                       int size,//共享内存大小

                                                                       int flags//共享内存的属性与权限

                                                 )

                                          为什么要key_t:

                                                        约定创建与访问的是同一个共享内存。Key为两个进程之间访问同一块共享内存的约定

注:key需要唯一性,因为我们不能保证我们自己定义的key的唯一性,所以为了保证kay的唯一性,我们需要用某个文件对应的整数来充当kay值,可以用ftok函数来将一个文件转化为一个kay值。(一般我们用两个进程的共同的工程目录文件来确定kay值)

                         ftok函数:

                                  #include<sys/ipc.h>

                                   key_t   ftok( const char * pathname,int  proj_id);

                                   参数二:一个控制因子。建议在0—255之间

                                          第三个参数:

                                                               方式|权限

                                                               方式:创建 IPC_CREAT  IPC_EXCL(如果内存已经创建,直接错误返回)

                                                               打开:0

                                                        常见的两种方式:

                                                                      创建:IPC_CREAT|IPC_EXCL | 0666;

                                                                      打开:0

                                   返回:

                                                 成功返回共享内存ID

                                                 失败返回-1                 

                            失败返回-1                 

                     B.根据ID得到共享内存,并且访问内存数据。

                                   挂载共享内存

void* shmat(int id,

                                                 void*startaddr,//0:系统指定首地址

                                                 intflags)//挂载方式,建议0默认读写,可以使用IPC_RDONLY

                             返回值:合法地址成功,-1失败

                     C.删除

                                   intshmctl(int id,//被操作的共享内存ID

                                                 inthow,//操作方式:一共三种操作

                                                 structshmid_ds*ds)//共享内存属性

                                   how:

                                                 IPC_STAT   

                                                 IPC_SET     //修改属性

                                                 IPC_RMID   //删除   参数三无用

案例代码:

ShmA.c

#include<stdio.h>

#include<stdlib.h>

#include<signal.h>

#include<sys/shm.h>

#include<sys/ipc.h>

void   main()

{

      key_t   key;

      int     shmid;

      int * p;

      //1.创建共享内存

      key=ftok( “.” , 255 );   //用当前路径的目录来确定kay值

      if(key == -1)  printf(“ftok error%m\n”) ,  exit( - 1 );

      shmid=shmget( key , 4 , IPC_CREAT|IPC_EXCL | 0666 );

      if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );

      //2.挂载共享内存

      p=shmat( shmid , 0 , 0);

      if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );

      //3.访问共享内存

      *p=999;

      //4.卸载共享内存

      shmdt(shmid);

      //删除共享内存

      shctl( shmid , IPC_RMID , 0);

}

不创建共享内存,只访问已有的

shmB.c

      //1.得到共享内存

      shmid=shmget( key , 4 ,0 );

       p=shmat( shmid , 0 , 0);

      printf(“%d\n”,*p);

2.      内核共享队列(有序)

            编程模型:

                                          2.1.创建共享队列/得到队列msgget

                                          2.2.使用队列(发送消息msgsnd/接收消息msgrcv)

                                          2.3.删除队列msgctl

                     创建共享队列

           #include<sys/msg.h>

                                   intmsgget(key_t,int); 除了不用指定大小,和shmget函数的参数一样                             

                     发送消息

                                   intmsgsnd(

                                                 intid,//消息队列ID

                                                 constvoid *msg,//要发送消息

                                                 size_tlen,//消息的长度

                                                 int flags//发送消息的方式,建议为0

                                          );

                                                 -1:失败

                                                  0:成功  

                                   第二个参数的消息有固定的格式

                                                        4字节:表示消息的类型

                                                        若干字节:消息内容。

                     消息格式:(该结构体需要我们自己定义)

                              struct  msgbuf{

                                   long   mtype; //消息类型

                                   char   mtext[1]; //消息内容

                              }

                                   第三个参数:

                                                        消息的大小,不包含类型的4个字节

              接收消息:

                       size_t   msgrcv(int id ,

void * msgp ,

size_t msgsz, ,

long msgtype , //那种类型的消息

int  msgflg);

                      返回:

                           -1:失败

                           大小:成功

               删除队列:msgctl 参数和shctl一样

#include<unistd.h>

#include<sys/msg.h>

#include<string.h>

struct  msgbuf

     long  type;

     char  data[32];

void main()

    key_t  key;

    int msgid;

    //1创建消息队列

     key= ftok(“ . ” , 254);

    if(key == -1) printf(“ftok error:%m\n”) , exit(-1);

    msgid= msgget(key,IPC_CREAT | IPC_EXCL|0666);

     if(msgid==-1) printf(“get error : %m\n”), exit(-1);

    //2构造消息

     struct  msgbuf msg;

    //3发送消息

     for(i=1;i<=10;i++)

    {

          msg.type=1;        //消息类型自己定义一个long类型

          sprintf(msg.data  , “Message:%d”,i);

          msgsnd(msgid ,&msg , strlen(msg.data) , 0);

    }

    //4删除队列

     //msgctl(msgid, IPC_RMID,0);

    //1得到消息队列

    key = ftok(“ . ” , 254);

    msgid= msgget(key,0);

    if(msgid== -1) printf(“get error : %m\n”), exit(-1);

    //3接收消息

     while(1)

         bzero(&msg,sizeof(msg));

         msgrcv(msgid , & msg sizeof(msg.data) , 1 , 0);

         printf(“%s\n”,msg.data);

说明:如果消息队列中没有消息了读取消息的程序会阻塞等待

当程序发送消息到队列中,一个程序读取了所以消息,队列中就没有消息,就无法再读取了,只能等待在发送消息后在读取消息。