zoukankan      html  css  js  c++  java
  • 详解linux进程间通信-消息队列

    前言:前面讨论了信号、管道的进程间通信方式,接下来将讨论消息队列。

      一、系统V IPC

      三种系统V IPC:消息队列、信号量以及共享内存(共享存储器)之间有很多相似之处。

      每个内核中的 I P C结构(消息队列、信号量或共享存储段)都用一个非负整数的标识符
    ( i d e n t i f i e r )加以引用。

      无论何时创建I P C结构(调用m s g g e ts e m g e ts h m g e t,都应指定一个关键字(k e y),关
    键字的数据类型由系统规定为 k e y _ t,通常在头文件< s y s / t y p e s . h >中被规定为长整型。关键字由
    内核变换成标识符。

      以上简单介绍了IPC,对接下来介绍的消息队列、信号量和共享内存有助于理解。

      二、消息队列

      1、简介

      消息队列是消息的链接表 ,存放在内核中并由消息队列标识符标识。我们将称消息队列为
    “队列”,其标识符为“队列 I D”。 m s g g e t用于创建一个新队列或打开一个现存的队列。 m s g s n d
    用于将新消息添加到队列尾端。每个消息包含一个正长整型类型字段,一个非负长度以及实际
    数据字节(对应于长度),所有这些都在将消息添加到队列时,传送给 m s g s n dm s g r c v用于从
    队列中取消息。我们并不一定要以先进先出次序取消息,也可以按消息的类型字段取消息。

      2、函数介绍

    • ftok函数

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

    key_t ftok(const char *pathname, int proj_id);//“/home/linux” , 'a'
    功能:生成一个key(键值)

    • msgget函数

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

    int msgget(key_t key, int msgflg);

    功能:创建或取得一个消息队列对象
    返回:消息队列对象的id 同一个key得到同一个对象
    格式:msgget(key,flag|mode);
    flag:可以是0或者IPC_CREAT(不存在就创建)
    mode:同文件权限一样

    • msgsnd函数

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    功能:将msgp消息写入标识为msgid的消息队列
    msgp:
    struct msgbuf {
    long mtype; /* message type, must be > 0 */消息的类型必须>0
    char mtext[1]; /* message data */长度随意
    };

    msgsz:要发送的消息的大小 不包括消息的类型占用的4个字节
    msgflg: 如果是0 当消息队列为满 msgsnd会阻塞
    如果是IPC_NOWAIT 当消息队列为满时 不阻塞 立即返回

    返回值:成功返回id 失败返回-1

    • msgrcv函数

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
    int msgflg);

    功能:从标识符为msgid的消息队列里接收一个指定类型的消息 并 存储于msgp中 读取后 把消息从消息队列中删除
    msgtyp:为 0 表示无论什么类型 都可以接收
    msgp:存放消息的结构体
    msgsz:要接收的消息的大小 不包含消息类型占用的4字节
    msgflg:如果是0 标识如果没有指定类型的消息 就一直等待
    如果是IPC_NOWAIT 则表示不等待

    • msgctl函数

    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    msgctl(msgid,IPC_RMID,NULL);//删除消息队列对象

      程序2-2将简单演示消息队列:

      ---  snd.c  ---

    #include "my.h"
    
    typedef struct{
        long type;
        char name[20];
        int age;
    }Msg;
    
    int main()
    {
        key_t key = ftok("/home/liudw",'6');
        printf("key:%x
    ",key);
    
        int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
        if(msgid<0)
        {   
            perror("msgget error!");
            exit(-1);
        }   
    
        Msg m;
        puts("please input your type name age:");
        scanf("%ld%s%d",&m.type,m.name,&m.age);
        msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
    
        return 0;
    }

      ---  rcv.c  ---

    #include "my.h"
     
    typedef struct{
        long type;
        char name[20];
        int age;
    }Msg;
    
    int main()
    {
        key_t key = ftok("/home/liudw",'6');
        printf("key:%x
    ",key);
    
        int msgid = msgget(key,O_RDONLY);
        if(msgid<0)
        {   
            perror("msgget error!");
            exit(-1);
        }   
    
        Msg rcv;
        long type;
        puts("please input type you want!");
        scanf("%ld",&type);
    
        msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(type),type,0);
        printf("rcv--name:%s age:%d
    ",rcv.name,rcv.age);
    
        msgctl(msgid,IPC_RMID,NULL);
        return 0;
    }

      运行演示:

      三、详解ftok函数 

    • ftok根据路径名,提取文件信息,再根据这些文件信息及project ID合成key,该路径可以随便设置。
    • 该路径是必须存在的,ftok只是根据文件inode在系统内的唯一性来取一个数值,和文件的权限无关。
    • proj_id是可以根据自己的约定,随意设置。这个数字,有的称之为project ID; 在UNIX系统上,它的取值是1到255;

      为了验证以上观点,对程序2-2稍作修改,将路径和proj_id修改:

      程序3-1如下:

      ---  snd.c  ---

    #include "my.h"
    
    typedef struct{
        long type;
        char name[20];
        int age;
    }Msg;
    
    int main()
    {
        key_t key = ftok("/home",'a');
        printf("key:%x
    ",key);
    
        int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
        if(msgid<0)
        {   
            perror("msgget error!");
            exit(-1);
        }   
    
        Msg m;
        puts("please input your type name age:");
        scanf("%ld%s%d",&m.type,m.name,&m.age);
        msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
    
        return 0;
    }

      ---  rcv.c  ---

    #include "my.h"
    
    typedef struct{
        long type;
        char name[20];
        int age;
    }Msg;
    
    int main()
    {
        key_t key = ftok("/home",'a');
        printf("key:%x
    ",key);
    
        int msgid = msgget(key,O_RDONLY);
        if(msgid<0)
        {   
            perror("msgget error!");
            exit(-1);
        }   
    
        Msg rcv;
        long type;
        puts("please input type you want!");
        scanf("%ld",&type);
    
        msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(type),type,0);
        printf("rcv--name:%s age:%d
    ",rcv.name,rcv.age);
    
        msgctl(msgid,IPC_RMID,NULL);
        return 0;
    }

      运行演示如下图:

     

      总结:主要介绍了进程间通信的消息队列,有疑问可以留言,一定即时解答。

  • 相关阅读:
    Delphi使用Indy、ICS组件读取网页
    用SendNotifyMessage代替PostMessage避免消息丢失
    LuaPlus的编译和引用
    如何转换和输出超大整数(64位)
    jQuery 源码:封装 Event
    jQuery 源码:操作样式
    jQuery 源码:元素位置
    模拟ES5 Array.prototype.reduce
    as 和 is 运算符以及安全的类型强制转换
    计算机编程基础
  • 原文地址:https://www.cnblogs.com/liudw-0215/p/8978945.html
Copyright © 2011-2022 走看看