程序間通訊(2)-訊息佇列

lethe1203發表於2024-04-04
Linux 中的訊息佇列是一種程序間通訊(IPC)機制,允許不同程序之間透過訊息進行通訊。

訊息佇列中的相關函式:

msgget:建立或開啟一個訊息佇列。
函式原型:int msgget(key_t key, int msgflg);
引數:
key:訊息佇列的鍵值,用於標識訊息佇列。
msgflg:標誌引數,用於指定訊息佇列的建立方式和許可權。
返回值:成功時返回訊息佇列的識別符號(非負整數),失敗時返回 -1。


msgctl:對訊息佇列進行控制。
函式原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
引數:
msqid:訊息佇列的識別符號。
cmd:控制命令,用於指定執行的操作。
buf:指向 struct msqid_ds 結構的指標,用於傳遞或接收訊息佇列的狀態資訊。
返回值:成功時返回0,失敗時返回 -1。


msgsnd:向訊息佇列傳送訊息。
函式原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
引數:
msqid:訊息佇列的識別符號。
msgp:指向要傳送的訊息的指標。
msgsz:訊息的大小(以位元組為單位)。
msgflg:標誌引數,用於指定傳送訊息的行為。
返回值:成功時返回0,失敗時返回 -1。


msgrcv:從訊息佇列接收訊息。
函式原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
引數:
msqid:訊息佇列的識別符號。
msgp:指向儲存接收訊息的緩衝區的指標。
msgsz:緩衝區的大小(以位元組為單位)。
msgtyp:指定所接收訊息的型別。
msgflg:標誌引數,用於指定接收訊息的行為。
返回值:成功時返回接收到的訊息的大小(以位元組為單位),失敗時返回 -1
對於ftok補充一點,ftok 函式是一個用於生成 System V IPC(Inter-Process Communication,程序間通訊)中鍵值的函式。在 System V IPC 中,諸如訊息佇列、共享記憶體和訊號量等資源都需要一個唯一的鍵值來標識。
ftok 函式的原型如下:
key_t ftok(const char *pathname, int proj_id);

它接受兩個引數:
pathname:一個指向檔案的路徑名的指標。通常情況下,你可以選擇一個現有的檔案,該檔案的存在與否對 ftok 函式的結果不會產生影響,因為它只關注檔案的索引節點號(inode number)和專案 ID(proj_id)。
proj_id:一個使用者定義的整數,用於生成鍵值的低8位。通常情況下,你可以為不同的 IPC 資源設定不同的專案 ID,以確保它們的鍵值不衝突。
ftok 函式將 pathname 引數指定的檔案的索引節點號和 proj_id 引數合併起來,然後透過一系列位操作生成一個唯一的鍵值。這個鍵值將作為 System V IPC 中資源的識別符號,用於建立或獲取相應的資源。
需要注意的是,ftok 函式的返回值是一個鍵值 key_t,這個鍵值會傳遞給 msgget、shmget 或 semget 等函式,用於建立或獲取對應的訊息佇列、共享記憶體或訊號量。
更多關於ftok函式的解析可見:ftok()函式深度解析
說白了ftok函式就是根據檔案生成一個key_t型別的值,key_t一般是一個長整型,那完全可用用一個長整型的數進行替換即可,前提是該長整型數沒有作為key_t使用

傳送訊息的程式msg1.c

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

#define MAX_MSG_SIZE 1024
#define MSG_TYPE 1

// 定義訊息結構體
struct msg_buffer {
    long msg_type;
    char msg_text[MAX_MSG_SIZE];
};

int main() {
    int i;
    int msg_id;
    key_t key;
    struct msg_buffer message;

    // 生成一個唯一的鍵值
    if ((key = ftok("lethe1203", 'B')) == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // 建立一個訊息佇列,如果不存在則建立,否則開啟
    if ((msg_id = msgget(key, 0666 | IPC_CREAT)) == -1) {    // 這裡完全可用把key替換為12345678等,去掉"生成一個唯一的鍵值"的步驟
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    printf("Sending multiple messages to the queue...\n");

    // 傳送多條訊息到佇列
    for (i = 1; i <= 5; ++i) {
        // 設定訊息的型別為 MSG_TYPE
        message.msg_type = MSG_TYPE;

        // 構造訊息內容
        sprintf(message.msg_text, "This is message %d from sender", i);

        // 傳送訊息
        if (msgsnd(msg_id, &message, sizeof(message.msg_text), 0) == -1) {
            perror("msgsnd");
            exit(EXIT_FAILURE);
        }

        printf("Message %d sent to queue.\n", i);

        // 為了演示,傳送完一條訊息後暫停五秒
        sleep(5);
    }

    printf("All messages sent to the queue.\n");

    return 0;
}

接收訊息的程式msg2.c:

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

#define MAX_MSG_SIZE 1024
#define MSG_TYPE 1

// 定義訊息結構體
struct msg_buffer {
    long msg_type;
    char msg_text[MAX_MSG_SIZE];
};

int main() {
    int msg_id;
    key_t key;
    struct msg_buffer message;

    // 生成一個唯一的鍵值
    if ((key = ftok("lethe1203", 'B')) == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // 獲取現有的訊息佇列,如果不存在則建立
    if ((msg_id = msgget(key, 0666 | IPC_CREAT)) == -1) {    // 這裡完全可用把key替換為12345678等,去掉"生成一個唯一的鍵值"的步驟
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    printf("Receiving messages from the queue...\n");

    // 從佇列中接收訊息
    while (1) {
        // 接收訊息
        if (msgrcv(msg_id, &message, sizeof(message.msg_text), MSG_TYPE, 0) == -1) {
            perror("msgrcv");
            exit(EXIT_FAILURE);
        }

        // 列印接收到的訊息
        printf("Message received: %s\n", message.msg_text);
    }

    return 0;
}

程式碼執行結果:

0

相關文章