IPC 共享内存和 消息队列(发送、接收、移除)以及键值的生成

一、消息对列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点:

消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。

消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。

消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

原型:

 #include <sys/msg.h>
 // 创建或打开消息队列:成功返回队列ID,失败返回-1,flag是打开队列的方式。
 int msgget(key_t key, int flag);
 // 添加消息:成功返回0,失败返回-1,ptr是消息,size是消息的大小,flag是标志位。
 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
 // 读取消息:成功返回消息数据的长度,失败返回-1,ptr是消息,size是消息的大小,type是消息的类型,flag是标志位。
 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
 // 控制消息队列:成功返回0,失败返回-1
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);

在以下两种情况下,msgget将创建一个新的消息队列:

如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
key参数为IPC_PRIVATE。

函数msgrcv在读取消息队列时,type参数有下面几种情况:

type == 0,返回队列中的第一个消息;
type > 0,返回队列中消息类型为 type 的第一个消息;
type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。

可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。(其他的参数解释,请自行Google之)

ftok函数
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok( const char * fname, int id )

fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。

接收代码演示

#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
struct msgbuf
{
        long mtype; //信息的类型,必须大于0
        char mtext[128];//信息数据存放
};
int main()
{
        //1.huoqu  duilie
        key_t key;
        key=ftok(".",'z');
        struct msgbuf readbuf;
        printf("key =%x\n",key);//%x   是六进制的形式
        struct msgbuf sendbuf={988,"thank you for reach"};
        int msgid=msgget(key,IPC_CREAT|0777);//IPC_CREAT|0777分别表示创建队列,和队列的权限
//      printf("ID=%x",msgid);
        if(msgid==-1){
                printf("creat fail\n");
        }
        msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),888,0);// 如果最后一个为0,以默认的方式来读,读不到的话会堵塞
        msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);
        printf("read from que:%s\n",readbuf.mtext);
        msgctl(msgid,IPC_RMID,NULL);
        return 0;
}

发送代码演示

 <sys/msg.h>
#include<string.h>
struct msgbuf
{
        long mtype;
        char mtext[128];
};
int main()
{
        key_t key;
        key=ftok(".",'z');
        printf("key =%x\n",key);
        struct msgbuf sendbuf={888,"this is message from quen"};//888  是消息类型
        struct msgbuf readbuf;
        int msgid=msgget(key,IPC_CREAT|0777);
        if(msgid==-1){
                printf("creat fail\n");
        }
        msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);
        msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),988,0);
        printf("return from get:%s\n",readbuf.mtext);
        msgctl(msgid,IPC_RMID,NULL);//IPC_RMID将消息队列的链表从内核中移除。一般最后一个写NULL,第一个是队列id。
        return 0;
}

共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。

特点:

共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。

因为多个进程可以同时操作,所以需要进行同步。

信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

思路:
(1)创建共享内存、若已经存在则直接打开
(2)映射将共享内存映射到进程独自的内存空间
(3)数据交换
(4)释放共享内存
(5)干掉共享内存
相关API

#include <sys/shm.h>
 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1,共享内存的大小必须以兆对齐。
 int shmget(key_t key, size_t size, int flag);
 // (映射)连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
 void *shmat(int shm_id, const void *addr, int flag);
 // 断开与共享内存的连接:成功返回0,失败返回-1
 int shmdt(void *addr); 
 // 控制共享内存的相关信息:成功返回0,失败返回-1
 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);

当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。

当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。

shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。

shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。

写端代码

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include <string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
        int shmid;
        char* shmaddr;
        key_t key;
        key=ftok(".",1);
        shmaddr=(char*)malloc(1024*4);
        shmid=shmget(key,1024*4,IPC_CREAT|0666);//IPC_CREAT|0666   创建共享内存,注明内存权限可读可写
        if(shmid==-1){
                printf("creat fail\n");
                exit(-1);//  异常退出返回-1,正常退出返回0.
        }
        else{
                shmaddr=shmat(shmid,0,0);//第二个一般写0,linux内核为我们自动的安排共享内存,第三个写0,表示映射进来的共享内存是可读可写的。
                printf("shmat ok\n");
                strcpy(shmaddr,"I am handsome");//将内容写入共享内存
        	    sleep(5);
                shmdt(shmaddr);//将映射的地址放入,卸载共享内存
                shmctl(shmid,IPC_RMID,0);//第三个参数用来存放卸载共享内存时产生的信息,不关心就写0.IPC_RMID删除共享内存
                printf("quit\n");

        }
        return 0;
}

读端代码

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include <string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
        int shmid;
        char* shmaddr;
        key_t key;
        key=ftok(".",1);
        shmaddr=(char*)malloc(1024*4);
        shmid=shmget(key,1024*4,0);// 读的时候只获取不创建所以最后的代码写0.
        if(shmid==-1){
                printf("creat fail\n");
                exit(-1);
        }
        else{
                shmaddr=shmat(shmid,0,0);
                printf("shmat ok\n");
                printf("data is %s\n",shmaddr);
                shmdt(shmaddr);
                printf("quit\n");
                shmctl(shmid,IPC_RMID,0);

        }
        return 0;
}

ipcs -m -------查看系统中有哪些共享内存
ipcrm -m + 共享内存ID号------删除共享内存

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值