詳解linux進程間通訊-消息隊列

前言:前面討論了信號、管道的進程間通訊方式,接下來將討論消息隊列。node

  1、系統V IPC

  三種系統V IPC:消息隊列、信號量以及共享內存(共享存儲器)之間有不少類似之處。linux

  每一個內核中的 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 >中被規定爲長整型。關鍵字由
內核變換成標識符。
spa

  以上簡單介紹了IPC,對接下來介紹的消息隊列、信號量和共享內存有助於理解。code

  2、消息隊列

  一、簡介

  消息隊列是消息的連接表 ,存放在內核中並由消息隊列標識符標識。咱們將稱消息隊列爲
「隊列」,其標識符爲「隊列 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用於從
隊列中取消息。咱們並不必定要以先進先出次序取消息,也能夠按消息的類型字段取消息。
對象

  二、函數介紹

  • ftok函數

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

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:同文件權限同樣ip

  • 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;
}

  運行演示:

  3、詳解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\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",'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;
}

  運行演示以下圖:

 

  總結:主要介紹了進程間通訊的消息隊列,有疑問能夠留言,必定即時解答。

相關文章
相關標籤/搜索