linux进程间通讯-消息队列


IPC对象

除了最原始的进程间通信方式信号、无名管道和有名管道外,还有三种进程间通信方式,这 三种方式称之为IPC对象。
IPC对象分类:消息队列、共享内存、信号灯集。
IPC对象也是在内核空间开辟区域,每一种IPC对象创建好之后都会将其设置为全局,并且会给其分配一个编号,只要找到唯一的这个编号就可以进行通信,所以不相关的进程可以通过IPC对象通信IPC对象创建好之后,会在当前系统中可见,只要不删除或者不关闭系统,就会一直存在。

查看已经创建的IPC对象:

ipcs 查看当前系统中所有创建的IPC对象 
ipcs ‐q 查看创建的消息队列 
ipcs ‐m 查看创建的共享内存 
ipcs ‐s 查看信号量 
ipcrm 删除IPC对象 
例如:ipcrm ‐q msqid 删除标号为msqid的消息队列

在这里插入图片描述
在这里插入图片描述

消息队列概述

消息队列的概念

消息队列是消息的链表,存放在内存中,由内核维护。

消息队列的特点

1、消息队列中的消息是有类型的。
2、消息队列中的消息是有格式的。 
3、消息队列可以实现消息的随机查询。消息不一定要以先进先出的次序读取,编程时可以 按消息的类型读取。
4、消息队列允许一个或多个进程向它写入或者读取消息。
5、与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删 除。
6、每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的。 
7、只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队 列,消息队列会一直存在于系统中。

在ubuntu 12.04中消息队列限制值如下

每个消息内容最多为8K字节 。
每个消息队列容量最多为16K字节 。
系统中消息队列个数最多为1609个 。
系统中消息个数最多为16384个 。
System V提供的IPC通信机制需要一个key值,通过key值就可在系统内获得一个唯
一的消 息队列标识符。 key值可以是人为指定的,也可以通过ftok函数获得。 如
果多个进程想通过IPC对象通信,则必须找到唯一的标识,而唯一的标识是由key
决定 的,所以只要key知道,则就可以实现多个进程通信。

ftok函数

在这里插入图片描述
使用ftok函数获取键值,只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管程序运行多少遍或者多少个进程或者键值,键值一定都是唯一的。
例子

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
int main(int argc, char const *argv[])
{
    //使用ftok函数获取键值
    //只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管程序运行多少遍或者多少个进程或者键值
    //键值一定都是唯一的
    key_t mykey;
    if((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    printf("key = %#x\n", mykey);
    return 0;
}

在这里插入图片描述

创建消息队列 – msgget( )

在这里插入图片描述
在这里插入图片描述

例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char const *argv[])
{
    //通过ftok函数获取ipc键值
    key_t mykey;
    if((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    printf("mykey = %#x\n", mykey);
    //通过msgget函数创建一个消息队列
    int msqid;
    if((msqid = msgget(mykey, IPC_CREAT | 0666)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    printf("msqid = %d\n", msqid);
    system("ipcs -q");
    return 0;
}

在这里插入图片描述

发送消息 – msgsnd( )

在这里插入图片描述
例子

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//发送数据并接收回复    全双工通讯
struct msgbuf
{
   long mtype;       
   char mtext[128];    
};
int main()
{
    struct msgbuf sendBuf={888,"this is message from quen"};
    struct msgbuf readBuf;
    key_t key;
    key=ftok(".",'z');                              //当前路径
    printf("key=%x\n",key);   
    //int msgget(key_t key, int flag);              创建消息队列
    //int msgId=msgget(0x1235,IPC_CREAT|0777);        如果没有就创建 权限是可读可写可执行
    int msgId=msgget(key,IPC_CREAT|0777);
    if(msgId==-1)
    {
        printf("get que failuer\n");
    }
    // int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);       //以非阻塞方式发送 发送给get
    printf("send over\n");
    msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);   //接收从get来的感谢
    printf("return from get:%s\n",readBuf.mtext);
    msgctl(msgId,IPC_RMID,NULL);                             //把创建的消息队列删除释放内存
    return 0;
}

接收消息 – msgrcv( )

在这里插入图片描述
注意:如果没有第四个参数指定的消息时,msgrcv函数会阻塞等待。
如果第四个参数为0,则按照先进先出的方式读取数据 。
if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 0, 0) == ‐1)
如果第四个参数为>0,则获取当前值得消息类型的数据 。
if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == ‐1)
如果第四个参数为<0,则获取当前值得绝对值内消息类型最小的数据。
例子

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//收到数据并回复感谢   全双工通讯
struct msgbuf
{
   long mtype;       
   char mtext[128];    
};
int main()
{
    struct msgbuf readBuf;
    key_t key;
    key=ftok(".",'z');                              //当前路径
    printf("key=%x\n",key);                         //用16进制打印出来
    //int msgget(key_t key, int flag);              创建消息队列
    //int msgId=msgget(0x1235,IPC_CREAT|0777);        如果没有就创建 权限是可读可写可执行
    int msgId=msgget(key,IPC_CREAT|0777); 
    if(msgId==-1)
    {
        printf("get que failuer\n");
    }
    //int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);      //0默认的方式接受消息 读不到888类型的消息会一直阻塞
    printf("read from que:%s\n",readBuf.mtext);        
    struct msgbuf sendBuf={988,"thank you for reach"};       
    msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);          //接收到信息后发射感谢
    msgctl(msgId,IPC_RMID,NULL);                             //把创建的消息队列删除释放内存
    return 0;
}

在这里插入图片描述

消息队列的控制

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char const *argv[])
{
    //使用ftok函数获取键值
    key_t key;
    if((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    //使用msgget函数创建一个消息队列
    int msgid;
    if((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    printf("msgid = %d\n", msgid);
    system("ipcs -q");
    //通过msgctl函数删除消息队列
    if(msgctl(msgid, IPC_RMID, NULL) == -1)
    {
        perror("fail to msgctl");
        exit(1);
    }
    system("ipcs -q");
    return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值