天天看點

詳解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 t、 s e m g e t或s 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 d。 m 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/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\n",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\n",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\n",rcv.name,rcv.age);

    msgctl(msgid,IPC_RMID,NULL);
    return 0;
}      

  運作示範:

詳解linux程式間通信-消息隊列
詳解linux程式間通信-消息隊列

  三、詳解ftok函數 

  • ftok根據路徑名,提取檔案資訊,再根據這些檔案資訊及project ID合成key,該路徑可以随便設定。
  • 該路徑是必須存在的,ftok隻是根據檔案inode在系統内的唯一性來取一個數值,和檔案的權限無關。
  • proj_id是可以根據自己的約定,随意設定。這個數字,有的稱之為project ID; 在UNIX系統上,它的取值是1到255;

  為了驗證以上觀點,對程式2-2稍作修改,将路徑和proj_id修改:

  程式3-1如下:

#include "my.h"

typedef struct{
    long type;
    char name[20];
    int age;
}Msg;

int main()
{
    key_t key = ftok("/home",'a');
    printf("key:%x\n",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;
}      
#include "my.h"

typedef struct{
    long type;
    char name[20];
    int age;
}Msg;

int main()
{
    key_t key = ftok("/home",'a');
    printf("key:%x\n",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\n",rcv.name,rcv.age);

    msgctl(msgid,IPC_RMID,NULL);
    return 0;
}      

  運作示範如下圖:

詳解linux程式間通信-消息隊列

 

詳解linux程式間通信-消息隊列

  總結:主要介紹了程序間通信的消息隊列,有疑問可以留言,一定即時解答。

作者:

柳德維

出處:

https://www.cnblogs.com/liudw-0215/

-------------------------------------------

個性簽名:獨學而無友,則孤陋而寡聞。做一個靈魂有趣的人!

如果覺得這篇文章對你有小小的幫助的話,記得在右下角點個“推薦”哦,部落客在此感謝!

萬水千山總是情,打賞一分行不行,是以如果你心情還比較高興,也是可以掃碼打賞部落客,哈哈哈(っ•̀ω•́)っ⁾⁾!

繼續閱讀