天天看點

Linux API-消息隊列:msgget、msgsnd、msgrcv、msgctl

消息隊列特性

  1. 消息隊列存在于Linux核心中,可以使資料雙向流動
  2. 資料在核心中,即使程序結束資料依然存在
  3. 消息隊列實際上是消息連結清單,每個隊列都有自己的辨別符

消息隊列API

  1. msgget——建立一個消息隊列
  2. msgsnd、msgrcv——添加資料到消息隊列、從消息隊列擷取資料
  3. msgctl——控制消息隊列

一、msgget——建立一個消息隊列

1.原函數

表頭檔案
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定義函數
int msgget(key_t key, int msgflg);
           

函數說明——建立和通路一個消息隊列

key——消息隊列的名稱(使用ftok()函數擷取)

msgflg——消息隊列的通路權限

傳回值——成功傳回此消息隊列的辨別符(非零整數)。失敗時傳回-1,失敗原因在errno中

2.示例

key_t key;
key = ftok(".",'z');

int msgId = msgget(key,IPC_CREAT|0777);//建立和通路一個消息隊列
           

二、msgsnd、msgrcv——添加資料到消息隊列、從消息隊列擷取資料

1.原函數

表頭檔案
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定義函數
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
           

函數說明——msgsnd()添加資料到消息隊列、msgrcv()從消息隊列擷取資料

msqid —— 由msgget()傳回的隊列辨別符

msgp —— 需要存放/讀取的結構體

msgsz —— 需要存放/讀取的大小

msgtyp —— 讀取消息隊列的位置

msgflg —— 預設值為0

傳回值——成功msgsnd()傳回0,msgrcv()傳回實際複制到mtext數組中的位元組數。錯誤兩個函數都傳回-1,errno表示錯誤

2.參數取值

msgp預設結構體如下:

struct msgbuf {
           long mtype;       /* message type, must be > 0 */
           char mtext[1];    /* message data */
       };
           

3.示例

struct msgbuf {
       long mtype;       /* message type, must be > 0 */
       char mtext[128];    /* message data */
};

struct msgbuf sendBuf = {988,"thank your welcome\n"};
struct msgbuf readBuf;

msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//從消息隊列擷取資料
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//添加資料到消息隊列
           

三、msgctl——控制消息隊列

1.原函數

表頭檔案
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定義函數
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
           

函數說明—— 控制消息隊列,它與共享記憶體的shmctl函數相似

msqid —— 由msgget()傳回的隊列辨別符

cmd —— 控制msqid_ds結構體指令

buf —— 記錄消息隊列的資訊(消息隊列模式和通路權限)(預設為NULL)

傳回值——成功時傳回0。失敗時傳回-1,errno表示錯誤

2.參數取值

command是将要采取的動作,它可以取3個值,

IPC_STAT:把msgid_ds結構中的資料設定為消息隊列的目前關聯值,即用消息隊列的目前關聯值覆寫msgid_ds的值。

IPC_SET:如果程序有足夠的權限,就把消息列隊的目前關聯值設定為msgid_ds結構中給出的值

IPC_RMID:删除消息隊列

msqid_ds預設結構體如下:

struct msqid_ds {
           struct ipc_perm msg_perm;     /* Ownership and permissions */
           time_t          msg_stime;    /* Time of last msgsnd(2) */
           time_t          msg_rtime;    /* Time of last msgrcv(2) */
           time_t          msg_ctime;    /* Time of last change */
           unsigned long   __msg_cbytes; /* Current number of bytes in
                                            queue (nonstandard) */
           msgqnum_t       msg_qnum;     /* Current number of messages
                                            in queue */
           msglen_t        msg_qbytes;   /* Maximum number of bytes
                                            allowed in queue */
           pid_t           msg_lspid;    /* PID of last msgsnd(2) */
           pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
       };
           

3.示例

消息隊列通信例程

程式1

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

struct msgbuf
{
        long mtype;       /* message type, must be > 0 */
        char mtext[50];    /* message data */
};

int main()
{
        struct msgbuf sndbuf={889,"Hello"};
        struct msgbuf rcvbuf;
        key_t key;
        int msgid;

        key=ftok(".",'k');//鍵值擷取

        msgid=msgget(key,IPC_CREAT|0777);//建立一個消息隊列 

        msgsnd(msgid,&sndbuf,sizeof(sndbuf.mtext),0);//添加資料到消息隊列 

        msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),888,0);//從消息隊列擷取資料

        printf("rcvbuf.mtype=%ld,rcvbuf.mtext=%s\n",rcvbuf.mtype,rcvbuf.mtext);

        msgctl(msgid,IPC_RMID,NULL);//删除消息隊列

        return 0;
}
           

程式2

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

struct msgbuf
{
        long mtype;       /* message type, must be > 0 */
        char mtext[50];    /* message data */
};

int main()
{
        struct msgbuf sndbuf={888,"World"};
        struct msgbuf rcvbuf;
        key_t key;
        int msgid;

        key=ftok(".",'k');//鍵值擷取

        msgid=msgget(key,IPC_CREAT|0777);//通路一個消息隊列 

        msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),889,0);//從消息隊列擷取資料

        printf("rcvbuf.mtype=%ld,rcvbuf.mtext=%s\n",rcvbuf.mtype,rcvbuf.mtext);

        msgsnd(msgid,&sndbuf,sizeof(sndbuf.mtext),0);//添加資料到消息隊列 


        msgctl(msgid,IPC_RMID,NULL);//删除消息隊列

        return 0;
}
           

運作結果:打開任意程式後消息隊列阻塞,等待另外一個程式将所需資料錄入,開啟另外一程式後兩程式達到消息通信的目的。

rcvbuf.mtype=889,rcvbuf.mtext=Hello

rcvbuf.mtype=888,rcvbuf.mtext=World

星辰~念

繼續閱讀