天天看點

Linux程序間通信之消息隊列消息隊列的結構消息隊列的各種操作

消息隊列的結構

0.消息隊列、消息緩存塊和通道

在學習“程序之間是如何使用消息隊列進行通信”之前,先要知道:

什麼消息隊列

什麼是消息緩存塊

什麼是通道

消息隊列

:一種資料結構,即隊列,其詳細内容暫不讨論

消息緩沖塊

:一種資料結構,用于存儲具體的資訊,程序之間通信的方法之一,代碼結構如下:

struct msgbuf{ long channel;//頻道号或通道号 char mtext[100];//消息内容,這裡的100是自定義值,可更改 }

頻道或通道

:并不真實存在,由

消息隊列

結構中的channel通道号分類,channel值相同的消息消息緩沖塊屬于同一

通道或頻道

(或說屬于同一類)
Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作
簡單的說,一個消息隊列通過一個唯一的key來生成這個消息隊列,而這個消息隊列中可能含有多個消息緩沖塊,區分這些不同的緩沖塊就是靠每個消息緩沖塊的頻道号或通道号。 再舉個通俗易懂的例子,我們把消息隊列比作傳送帶,把傳送帶上一件件物品比作消息緩沖塊,為了區分這些不同種類的物品,我們給它們做上标記,也就是這裡的頻道号或通道号,以便于我們接收到這些不同的物品能分門别類。

消息隊列的各種操作

1.建立/打開消息隊列

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

//用于建立一個新的或打開一個已經存在的消息隊列
int msgget(key_t key,int flag);
//傳回值:-1表示失敗,成功傳回建立/打開的消息隊列辨別符id
           

(1)msgget參數:消息隊列對象的關鍵字key

每個消息隊列有一個唯一的辨別符id,key就是消息隊列的關鍵字

函數将key與已有的消息隊列對象的關鍵字進行比較來判斷消息隊列對象是否已經建立

(2)msgget參數:操作消息隊列的權限flag

IPC_CREAT:建立新的消息隊列。

IPC_EXCL:與IPC_CREAT一同使用,表示如果要建立的消息隊列已經存在,則傳回錯誤。 IPC_NOWAIT:讀寫消息隊列要求無法滿足時,不阻塞

0:如果是打開檔案,即檔案已存在,寫0

(3)★生成key

系統建立IPC通訊 (消息隊列、信号量和共享記憶體) 時必須指定一個ID值(關鍵字key)。通常情況下,該ID值(關鍵字key)通過ftok函數得到

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

key_t ftok(const char *pathname, int proj_id);
//pathname就是你指定的檔案名(路徑),要求檔案必須存在,一般使用目前目錄,如:
key_t key;
key = ftok(".", );//這樣就是将pathname設為目前目錄
//id是子序号,雖然是int類型,但是隻使用8bits(1-255)
//傳回值:失敗傳回-1,成功傳回key_t值
           

ftok工作原理

在一般的UNIX實作中,是将檔案的索引節點号取出,前面加上子序号得到key_t的傳回值。

如指定檔案的索引節點号為65538,換算成16進制為0x010002,而你指定的ID值為38,換算成16進制為0x26,則最後的key_t傳回值為0x26010002。

查詢檔案索引節點号的方法是: ls -i

簡單來說:ftok的作用就是保證生成的消息隊列關鍵字key唯一

代碼如下:

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

int main()
{
//第一步:生成消息隊列唯一的key,用來建立一個消息隊列
    key_t key=ftok(".",'a');
    if(key == -)
        perror("ftok"),exit();
 //第二步:根據這個唯一的key,建立消息隊列
    int id=msgget(key,IPC_CREAT|);
    if(id == -)
        perror("msgget"),exit();
    printf("create success\n");
    return ;
}
           

2.檢視消息隊列

指令:ipcs -q
Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作
執行個體如下:
Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作

3.如何手工删除消息隊列

指令:ipcrm -Q [key]

執行個體如下:

Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作

4.往消息隊列裡寫資料

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

//調用成功傳回0,不成功傳回-1
int msgsnd(int msqid,const void* msgp,ssize_t msgsz,int msgflg)
//msqid 想要寫入内容的消息隊列辨別符id,msqid是msgget的傳回值,也用來辨別消息隊列
//msgp 臨時建立的消息隊列結構體對象的指針
//★上面兩個參數的關系:
//①先将想要寫入的内容寫入“msgp指向的消息隊列結構體對象”裡
//②再将“msgp指向的消息隊列結構體對象”裡的内容放入“msqid對應的消息隊列”中
//③進而實作對“msqid對應的消息隊列”的寫入
//msgsz 要寫入的消息的大小,不包括通道号,即char mtext[100]的大小
//msgflg 為0表示阻塞方式,設定IPC_NOWAIT 表示非阻塞方式
           

代碼如下:

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

struct msgbuf {

    long channel;
    char mtext[];
};

int main( void )
{
    int id = msgget(, ); 
    //打開消息隊列,0x61021685是剛才建立的消息隊列關鍵字
    //第二個參數為0,表示這是打開消息隊列而不是建立,即該消息隊列存在
    if ( id == - )
        perror("msgget"),exit();

    struct msgbuf mb;
    printf("channel:");
    scanf("%ld", &mb.channel);
    printf("text:");
    scanf("%s", mb.mtext);

    int r = msgsnd(id, &mb, strlen(mb.mtext), );
    if ( r == - )
        perror("msgsnd"),exit();

}
           
Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作

5.從消息隊列裡讀資料

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

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//msqid 想要讀取内容的消息隊列辨別符id,mspid是msgget的傳回值,也用來辨別消息隊列
//msgp 臨時建立的消息隊列結構體對象的指針
//★上面兩個參數的關系:
//①先将“msqid對應的消息隊列”裡的内容放入“msgp指向的消息隊列結構體對象”中
//②再從“msgp指向的消息隊列結構體對象”中讀取想要讀取的内容
//③進而實作對“msqid對應的消息隊列”的讀取
//msgsz 消息大小,不包括通道号,隻指消息内容大小,即char mtext[100]的大小
//msgtyp 想接收的消息所在的通道号,通道号如果寫0,表示按照順序接收消息隊列
//msgflg 為0表示阻塞方式,設定IPC_NOWAIT 表示非阻塞方式
           

代碼如下:

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

struct msgbuf {

    long channel;
    char mtext[];
};

int main( void )
{
    int id = msgget(, ); 
    //打開消息隊列,0x61021685是剛才建立的消息隊列關鍵字
    //第二個參數為0,表示這是打開消息隊列而不是建立,即該消息隊列存在
    if ( id == - )
        perror("msgget"),exit();

    struct msgbuf mb;
    printf("channel:");
    int channel;
    scanf("%d", &channel);

    ssize_t r=msgrcv(id,&mb,,channel,);
    if(r == -)
        perror("msgrcv"),exit();
    printf("%s\n",mb.mtext);
}
           
Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作

6.使用函數修改(包括删除)消息隊列

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

//msgctl系統調用對msqid辨別的消息隊列執行cmd操作列
//傳回值:成功傳回0,失敗傳回-1
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//msqid 消息隊列辨別符,mspid是msgget的傳回值,也用來辨別消息隊列
//cmd:包括以下三種 
//IPC_STAT
//讀取消息隊列的資料結構msqid_ds,并将其存儲在buf指定的位址中。
//IPC_SET
//設定消息隊列的資料結構msqid_ds中的ipc_perm元素的值。這個值取自buf參數。
//IPC_RMID
//從系統核心中移走消息隊列,即删除消息隊列
//buf 配合IPC_RMID使用,設為0,即buf為NULL;其他兩個情況暫不讨論
//
           

代碼如下:

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

int main()
{
    int id=msgget(,IPC_CREAT|);
    if(id == -)
        perror("msgget"),exit();
    printf("create success\n");
    if(msgctl(id,IPC_RMID,) == -)
        perror("msgtcl"),exit();
    printf("msgctl success\n");
    return ;
}
           
Linux程式間通信之消息隊列消息隊列的結構消息隊列的各種操作

本文轉載自: https://blog.csdn.net/w_y_x_y/article/details/80073968,文章内容有所修改

繼續閱讀