lv5 嵌入式开发-11 消息队列

掌握:消息队列机制、打开/创建消息队列、发送消息、接收消息

1 消息队列

消息队列是System V IPC对象的一种

消息队列由消息队列ID来唯一标识

消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等

消息队列可以按照类型来发送/接收消息

消息队列结构

内核中已实现的数据结构:链表

进程A放入数据,进程B可访问并取出。

lv5 嵌入式开发-11 消息队列_第1张图片

2 消息队列使用步骤 

发送端:

        1 申请key

        2 打开/创建消息队列   msgget

        3 向消息队列发送消息   msgsnd

接收端:

        1 打开/创建消息队列   msgget

        2 从消息队列接收消息   msgrcv

        3 控制(删除)消息队列   msgctl

2.1 消息队列创建/打开 – msgget

#include 
#include 
int msgget(key_t key, int msgflg);
  • 成功时返回消息队列的id,失败时返回EOF  
  • key 和消息队列关联的key  IPC_PRIVATE 或 ftok  
  • msgflg  标志位  IPC_CREAT|0666  没有创建,有则打开。

lv5 嵌入式开发-11 消息队列_第2张图片

示例

int main() {
   int msgid;
   key_t key;

   if ((key = ftok(“.”, ‘q’)) == -1) {
      perror(“ftok”);  exit(-1);
   }
   if ((msgid = msgget(key, IPC_CREAT|0666)) < 0) {
      perror(“msgget”); exit(-1);
   }
   …… 
   return 0;
}

2.2 消息发送 – msgsnd

#include 
#include 
int msgsnd(int msgid, const void *msgp, size_t size,
            int msgflg);
  • 成功时返回0,失败时返回-1  
  • msgid   消息队列id  
  • msgp    消息缓冲区地址  
  • size    消息正文长度  
  • msgflg   标志位 0 或 IPC_NOWAIT

        0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列

        IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回

lv5 嵌入式开发-11 消息队列_第3张图片

2.3 消息格式

  • 通信双方首先定义好统一的消息格式
  • 用户根据应用需求定义结构体类型
  • 首成员类型必须为long,代表消息类型(正整数)
  • 其他成员都属于消息正文
  • 消息长度不包括首类型 long

示例:

typedef  struct {
   long mtype;
   char mtext[64];
} MSG;

#define LEN (sizeof(MSG) – sizeof(long))

int main() {
    MSG buf;
    ……
    buf.mtype = 100; 
    fgets(buf.mtext, 64, stdin);
    msgsnd(msgid, &buf,LEN, 0);
    …… 
    return 0;
}

注意:

1 消息结构必须有long类型的msg_type字段,表示消息的类型。

2消息长度不包括首类型 long

 

2.4 消息接收 – msgrcv

 #include 
 #include 
 int msgrcv(int msgid, void *msgp, size_t size, long msgtype,
                   int msgflg);
  • 成功时返回收到的消息长度,失败时返回-1  
  • msgid   消息队列id  
  • msgp   消息缓冲区地址  
  • size   指定接收的消息长度  
  • msgtype   指定接收的消息类型    
  • msgflg   标志位   0 或 IPC_NOWAIT        

        msgtype=0:收到的第一条消息,任意类型。

        msgtype>0:收到的第一条 msg_type类型的消息。

        msgtype<0:接收类型等于或者小于msgtype绝对值的第一个消息

例子:如果msgtype=-4,只接受类型是1、2、3、4的消息

lv5 嵌入式开发-11 消息队列_第4张图片

示例 

typedef  struct {
    long mtype;
    char mtext[64];
}MSG;

#define  LEN  (sizeof(MSG) – sizeof(long))

int main() {
    MSG buf;
    ……
    if (msgrcv(msgid, &buf,LEN, 200, 0) < 0) {
       perror(“msgrcv”);
       exit(-1);
    }
    ……
}

2.5 控制消息队列 – msgctl

#include 
#include 
int msgctl(int msgid, int cmd, struct msqid_ds *buf);
  • 成功时返回0,失败时返回-1  
  • msgid    消息队列id  
  • cmd    要执行的操作  IPC_STAT / IPC_SET / IPC_RMID  (删除)
  • buf   存放消息队列属性的地址

lv5 嵌入式开发-11 消息队列_第5张图片

2.6 示例(编写实现两个进程实现消息队列通信的程序)

 示例:发送消息队列

#include 
#include 
#include 
#include 

typedef struct{
    long msg_type;
    char buf[128];
}msgT;    

#define MSGLEN  (sizeof(msgT)-sizeof(long))

int main(){
    key_t key;
    int msgid;
    int ret;
    msgT msg;
    key = ftok(".",100);                //创建key
    if(key<0){
        perror("ftok");
        return 0;
    }
    msgid = msgget(key,IPC_CREAT|0666);  //创建消息队列
    if(msgid<0){
        perror("msgget");
        return 0;
    }

    msg.msg_type = 1;
    strcpy(msg.buf,"this msg type 1");
    ret = msgsnd(msgid,&msg,MSGLEN,0);
    if(ret<0){
        perror("msgsnd");
        return 0;
    }    

    msg.msg_type = 2;
    strcpy(msg.buf,"this msg type 2");
    ret = msgsnd(msgid,&msg,MSGLEN,0);
    if(ret<0){
        perror("msgsnd");
        return 0;
    }
    msg.msg_type = 3;
    strcpy(msg.buf,"this msg type 3");
    ret = msgsnd(msgid,&msg,MSGLEN,0);
    if(ret<0){
        perror("msgsnd");
        return 0;
    }
    msg.msg_type = 4;
    strcpy(msg.buf,"this msg type 4");
    ret = msgsnd(msgid,&msg,MSGLEN,0);
    if(ret<0){
        perror("msgsnd");
        return 0;
    }
    msg.msg_type = 5;
    strcpy(msg.buf,"this msg type 5");
    ret = msgsnd(msgid,&msg,MSGLEN,0);
    if(ret<0){
        perror("msgsnd");
        return 0;
    }

}

查看消息队列 

lv5 嵌入式开发-11 消息队列_第6张图片

示例:消息接收和删除

#include 
#include 
#include 
#include 

typedef struct{
    long msg_type;
    char buf[128];
}msgT;    

#define MSGLEN  (sizeof(msgT)-sizeof(long))
int main(){
    
    int msgid;
    key_t key;
    msgT msg;
    int ret;
    key = ftok(".",100);
    if(key<0){
        perror("ftok");
        return 0;
    }    
    msgid = msgget(key,IPC_CREAT|0666);
    if(msgid<0){
        perror("msgget");
        return 0;
    }
    int count=0;           
    while(1){     //连续接收
        //ret = msgrcv(msgid,&msg,MSGLEN,3,0);   //只接收类型3
        //ret = msgrcv(msgid,&msg,MSGLEN,-3,0);   //只接收类型1、2、3
        ret = msgrcv(msgid,&msg,MSGLEN,0,0);     //全部接收
        if(ret<0){ 
            perror("msgrcv");
            return 0;
        } 
        count++;
        if(count>3){
            break;
        }
        printf("receiv msg type=%d,buf=%s\n",(int)msg.msg_type,msg.buf);
    }

    ret = msgctl(msgid,IPC_RMID,NULL);
    if(ret<0){
        perror("msgctl");
        return 0;
    }    

}

你可能感兴趣的:(嵌入式开发,linux)