4.进程通信篇(4--消息队列)-2020物联网_Linux高级程序设计全套教程(通俗易懂)

6.消息队列之IPC对象

1、信号、无名管道和有名管道是最原始的进程通信方式,除此外还有三种通信,称之为IPC对象;

2、IPC对象分为:消息队列、共享内存、信号灯集

3、IPC对象也是在内核空间中开辟区域,每一种ipc对象创建好之后都会将其设置为全局。并且会给其分配一个编号,只要找到唯一的这个编号就可以通信了,所以不相关的进程可以通过ipc对象通信;

4、ipc对象创建好之后,会在当前系统中可见,只要不删除或者不关闭系统,就会一直存在;

6.01消息队列概述

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

消息队列的特点:

1、消息队列中的消息是有类型的

2、消息队列中的消息是有格式的

3、消息队列可以实现消息随机查询,消息不一定要以先进先出的次序,编程时可以按照消息的类型读取

4、消息队列允许一个或者多个进程向它写入或者读取消息

5、与无名管道、命名管道一样,从消息队列中读出的消息数据会被删除

6、每个消息队列都有消息队列标识,消息队列的标识符在整个系统中是唯一的

7、只有内核重启或者 人工删除消息队列时,该消息队列才会被删除,否则一直存在系统中;

****************在每个系统中消息队列是有限制的**********

每个消息内容最多为8K、

每个消息队列容量最多为16K

系统中消息队列个数最多为1609个

系统中消息个数最多为16384个

 

System V提供的IPC通信机制需要一个key值,通过key值就可以在系统内获得一个唯一的消息队列的标识符。key值可以通过人为指定,也可以通过ftok函数获得;

ftok函数

#include <sys/types.h>

#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id)

功能:获得项目相关的唯一的ipc键值

参数:pathname(任意一个文件名、路径名或者目录名)因为对应的inode号是唯一的

proj_id:项目id,非0整数,只有8位有效

返回值:成功返回Key,失败-1

ftok实例:如果两个参数一致是不是每次key值都一样呢?

#include<stdio.h>
#include<stdlib.h>
#include<unstd.h>

int main(int argc, char **argv)
{ 
    key_t mykey;
    if((ftok(".", 100)) == -1)
    {
        perror();
        exit(1);
    }    
    
    printf("%#X\n", mykey);
    return 0;
}

 

6.03创建消息队列----msgget

命令ipcs或者ipcs -q可以查看

#include<sys/msg.h>

int msgget(key_t key, int msgflag)

功能:创建一个新的或者打开一个已经存在的消息队列,不同的进程调用此函数,只要用相同的key值就能得到用一个消息队列的标识符;

参数:key:ipc键值

msgflag:标识函数的行为以及消息队列的权限

msgflag的取值:一般设置为:IPC_CREATE | IPC_EXECL  | 0777

IPC_CREAT 创建消息队列

IPC_EXECL 检查消息队列是否存在

成功返回消息队列标识符,失败返回-1

实例创建消息队列:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflag);

//执行后ipcs -q可以查看
//ipcrm -a msqid 就可以删除

#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 **argv)
{
    int msqid=0;

    //通过ftok函数获取key值
    if((mykey = ftok(".", 100) == -1))
    {
        exit(-1);
    }
    
    printf("%#x\n", mykey);

    //通过msgget函数创建一个消息队列
    if( (msqid = msgget(mgkey, IPC_CEEAT | 0666) )== -1)
    {   
        exit(-1); 
    }
    
    system("ipcs -q")

    return  0;
//执行后ipcs -q可以查看
//ipcrm -a msqid 就可以删除
}

 

6.04消息队列----发送消息

#include<sys/msg.h>

int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflag);

功能:将新的消息添加到消息队列

参数:msgid 消息队列的标识符

msgq 待发送消息的结构体地址

msgsz 消息正文的字节数

msgflag 函数的控制属性

     0:msgsnd调用阻塞直到条件满足为止

     IPC_NOWAIT:若消息没有立即发送,则调用该消息的进程立即返回

返回:成功0 失败-1

 

消息队列的格式:

typedef struct _msg

{

long mtype; //消息的类型

char mtext[100];//消息正文

。。。。//消息的正文可以有多个成员

}MSG; 

消息类型必须是长整型的,而且必须要是结构体类型的第一个成员,类型下面是消息正文,正文可以有多个成员

#defined N 128
#difined MSGTEXT_SIZE sizeof(MSG)-sizeof(long)

typedef struct
{
    long msg_type;//消息类型必须在结构体的第一个
    char nsg_text[N];//正文
}MSG;

int main(int argc. char **argv)
{
    int msqid=0;

    //通过ftok函数获取key值
    if((mykey = ftok(".", 100) == -1))
    {
        exit(-1);
    }
    
    printf("%#x\n", mykey);

    //通过msgget函数创建一个消息队列
    if( (msqid = msgget(mgkey, IPC_CEEAT | 0666) )== -1)
    {   
        exit(-1); 
    }
    
    system("ipcs -q")



    MSG msg1={1, "hello world1"};

    MSG msg2={4, "hello world2"};

    MSG msg3={3, "hello world3"};

    MSG msg4={2, "hello world4"};


    if(msgsnd(msgid, &msg1, MSGTEXT_SIZE, 0) == -1)
    {    
    }

    if(msgsnd(msgid, &msg2, MSGTEXT_SIZE, 0) == -1)
    {    
    }
    if(msgsnd(msgid, &msg3, MSGTEXT_SIZE, 0) == -1)
    {    
    }
    if(msgsnd(msgid, &msg4, MSGTEXT_SIZE, 0) == -1)
    {    
    }

    system("ipcs -q");







    return  0;
//执行后ipcs -q可以查看
//ipcrm -a msqid 就可以删除

}

每执行一次,往里面写一次!

 

6.05消息队列----接收消息

#include <sys/msg.h>

ssize_t msgrcv(int msgid, void *msgp,  size_t msgsz, long msgtyp, int msgflag);

功能:从标识符为msgqid的消息队列中接收一个消息,一旦接收消息成功,则消息在消息队列中被删除

参数:msgqid:消息队列的标识符,代表要从哪里获取消息

msgp 存放消息结构的地址

msgsz: 消息正文的字节数

msgtyp:消息的类型,可以有一下几种类型:

    msgtyp=0; 返回队列种的第一个消息

    msgtyp>0;返回队列种的消息类型为msgtyp的消息

    msgtyp<0;返回队列种消息类型小于或者等于msgtyp绝对值的消息,如果这种消息由若干个,则取类型最小的消息

 

注意:1、若消息队列种由多种类型的消息,msgrcv获取消息的时候按照消息类型获取,不是先进先出;2、在获取某类型消息的时候,若丢列种由多条此类型的消息,则获取最先添加的消息;即先进先出的原则;

msgflag:函数的控制属性

 0:msgrcv调用阻塞直到接收消息成功为止

MSG_NOERROR:若返回的消息字节数比nbytes字节数多,则消息就会截短到nbytes字节,且不通知消息发送进程

IPC_NOWAIT:调用进程会立即返回,若没有收到消息则立即返回-1

注意:msgrcv是会阻塞的,如果接收指定的消息类型不纯在的时候就会发送阻塞!!!!!!

实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

defined N 128

typedef struct {
    long msg_type;
    char msg_text[N];
}MSG;

#defined MSGTEXT_SIZE         sizeof(MSG) - sizeof(long)


int main(int argc. char **argv)
{
    int msqid=0;

    //通过ftok函数获取key值
    if((mykey = ftok(".", 100) == -1))
    {
        exit(-1);
    }
    
    printf("%#x\n", mykey);

    //通过msgget函数创建一个消息队列
    if( (msqid = msgget(mgkey, IPC_CEEAT | 0666) )== -1)
    {   
        exit(-1); 
    }
    
    system("ipcs -q")

//通过msgrcv接收消息队列种的消息    

    if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 0, 0) == -1)
    {  }
        
    if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == -1)
    {  }


    printf("recv_msg = %s\n", msg.msg_text);
    
    
    system("ipcs -q");

        

    

    

    return  0;
//执行后ipcs -q可以查看
//ipcrm -a msqid 就可以删除
}

 

6.05消息队列控制

#include <sys/msg.h>

int msgctl(int msqid,          int cmd,         struct msqid_ds *buf);

功能:对消息队列进行各种控制,如修改消息队列属性,或者删除消息队列

参数:msqid 消息队列的标识符

cmd 函数功能的控制

buf: msqid_ds数据类型的地址,用来存放或者更改消息队列的属性

cmd:函数功能的控制

  IPC_RMID 删除由msqid指示的消息队列,将它从系统中删除并破环相关的数据结构

  IPC_STAT 将msqid相关的数据结构中的各个元素的当前值存放到由buf指向的结构中

  IPC_SET  将msqid相关的数据结构中的元素设置为由buf指向的结构中的对应值

成功返回0

 

int main(int argc. char **argv)
{
    int msqid=0;

    //通过ftok函数获取key值
    if((mykey = ftok(".", 100) == -1))
    {
        exit(-1);
    }
    

    //通过msgget函数创建一个消息队列
    if( (msqid = msgget(mgkey, IPC_CEEAT | 0666) )== -1)
    {   
        exit(-1); 
    }
    
    system("ipcs -q");


    if(msgctl(msgid, IPC_RMID, null) == -1)
    {}
    
    
    system("ipcs -q");

    return 0;
    
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuckyDog0623

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值