进程间通信——消息队列和共享内存

消息队列
·消息队列提供了从一个进程向另一个进程发送一块数据的方法;
·每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值;
·消息队列也具有管道的缺点,即每个消息的最大长度是有上限的,每个消息队列的总的字节数是有上限的,系统上消息队列的总数也有一个上限。

消息队列在内核中的表示
这里写图片描述

消息队列函数
1、创建和访问消息队列

函数原型:int msgget(key_t key,int msgflg);
参数:key:消息队列的名字;  
     msgflg: 创建时为:IPC_CREAT | 0644(权限)
             打开时为:0
     返回值:成功返回消息队列的标识码;失败返回-1.

创建一个消息队列msg.c的代码如下:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/msg.h>
  5 
  6 int main()
  7 {
  8   int id = msgget(1234,IPC_CREAT | 0644);
  9   if(id == -1)
 10    {
 11      perror("msgget");
 12      exit(1);
 13    }
 14   printf("creat ok!\n");
 15 }

2、查看消息队列: ipcs -q

3、消息队列的控制函数

函数原型:int msgctl(int msgid,int cmd,struct msgid_ds *buf);
参数:msqid:由msgget函数返回的消息队列标识码;
     cmd:将要采取的动作;
     返回值:成功返回0,失败返回-1.

4、把一条消息添加到消息队列中

函数原型:int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);
参数: msgid:由msgget函数返回的消息队列标识码;
      msgp:是一个指针,指向准备发送的消息;
      msgsz:是msgp指向的消息长度,该长度不包含保存消息类型的long int长整型;
      msgflag:一般设为0.
返回值:成功返回0;失败返回-1.

将消息添加到消息队列中的代码如下:

 1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/msg.h>
  5 #include<string.h>
  6 
  7 struct msgbuf{
  8   long type;
  9   char text[1];
 10 }
 11 
 12 int main()
 13 {
 14   int id = msgget(1234,0);
 15   struct msgbuf sm;
 16   printf("channel:");
 17   scanf("%d",&sm.type);
 18   printf("text:");
 19   scanf("%s",sm.text);

5、从一个消息队列接收消息

函数原型:ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtype, int msgflg);
参数: msgid:由msgget函数返回的消息队列标识码;
      msgp:是一个指针,指向准备接收的消息;
      msgsz:是msgp指向的消息长度,该长度不包含保存消息类型的long int长整型;
      msgtype:类型号
      msgflag:一般设为0.
返回值:成功返回接收的字符个数;失败返回-1.

6、删除消息队列 :
ipcrm -Q key

共享内存
共享内存是最快的进程间通信。(进程不再通过执行进入内核的系统调用来传递彼此的数据)

共享内存示意图
这里写图片描述

共享内存函数
1、创建/打开共享内存

原型:int shmget(key_t key, size_t size, int shmflg);
参数:key: 共享内存段的名字;
     size:共享内存大小;
     shmflg:创建:IPC_CREAT | 0644(权限);
             打开:0
返回值:成功返回标识码;失败返回-1.

2、将共享内存映射到自己的地址空间

原型:void* shmat(int shmid, const void* shmaddr, int shmflg);
参数:shmid: 共享内存标识;
     shmaddr:指定映射的地址;
     shmflg:一般为0.
返回值:成功返回指向映射到的虚拟地址空间的起始位置的指针;失败返回-1.

3、将共享内存段与当前进程脱离

原型:int shmdt(const void* shmaddr);
参数:shmaddr:由shmat所返回的指针。
返回值:成功返回0;失败返回-1.

4、控制共享内存

原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:shmid:由shmget返回的共享内存标识码;
     cmd:将要采取的动作;
     buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1.

共享内存有关函数的测试代码:

Makefile

  1 .PHONY:all
  2 all:server client
  3 
  4 client:client.c comm.c
  5         gcc -o $@ $^
  6 server:server.c comm.c
  7         gcc -o $@ $^
  8 .PHONY:clean
  9 clean:
 10         rm -f client server

comm.h

  1 #ifndef _COMM_H_
  2 #define _COMM_H_
  3 
  4 #include<stdio.h>
  5 #include<sys/types.h>
  6 #include<sys/ipc.h>
  7 #include<sys/shm.h>
  8 
  9 #define PATHNAME "."
 10 #define PROJ_ID 0x6666
 11 
 12 int createshm(int size);
 13 int destroyshm(int shmid);
 14 int getshm(int size);
 15 
 16 #endif
~           

comm.c

  1 #include"comm.h"
  2 
  3 static int commshm(int size,int flags)
  4 {
  5   key_t _key = ftok(PATHNAME,PROJ_ID);
  6   if(_key < 0)
  7   {
  8      perror("ftok");
  9      return -1;
 10   }
 11   int shmid = 0;
 12   if((shmid = shmget(_key,size,flags)) < 0)
 13   {
 14      perror("shmget");
 15      return -2;
 16   }
 17   return shmid;
 18 }
 19 
 20 int destoryshm(int shmid)
 21 {
 22   if(shmctl(shmid,IPC_RMID,NULL) < 0)
 23   {
 24      perror("shmctl");
 25      return -1;
 26   }
 27   return 0;
 28 }
 29 
 30 int createshm(int size)
 31 {
 32   return commshm(size,IPC_CREAT | IPC_EXCL | 0666);
 33 }
 34 
 35 int getshm(int size)
 36 {
 37   return commshm(size,IPC_CREAT);
 38 }

server.c

  1 #include "comm.h"
  2 
  3 int main()
  4 {
  5   int shmid = createshm(4096);
  6   char *addr = shmat(shmid,NULL,0);
  7   sleep(2);
  8   int i = 0;
  9   while(i++ < 26)
 10   {
 11      printf("client# %s\n",addr);
 12      sleep(1);
 13   }
 14   shmdt(addr);
 15   sleep(2);
 16   destoryshm(shmid);
 17   return 0;
 18 }

client.c

  1 #include "comm.h"
  2 
  3 int main()
  4 {
  5   int shmid = getshm(4096);
  6   sleep(1);
  7   char *addr = shmat(shmid,NULL,0);
  8   sleep(2);
  9   int i = 0;
 10   while(i < 26)
 11   {
 12      addr[i] = 'A'+i;
 13      i++;
 14      addr[i] = 0;
 15      sleep(1);
 16   }
 17   shmdt(addr);
 18   sleep(2);
 19   return 0;
 20 }

猜你喜欢

转载自blog.csdn.net/weixin_41289858/article/details/80684299