linux进程间通信:system V消息队列
文章目錄
- 基本介紹
- 編程接口
- 代碼實例
- 消息隊列的發(fā)送和接收
- 消息隊列中的消息對象的屬性控制
基本介紹
- 支持不同進(jìn)程之間以消息(messages)的形式進(jìn)行數(shù)據(jù)交換,消息能夠擁有自己的標(biāo)識,且內(nèi)核使用鏈表方式進(jìn)行消息管理。
- 進(jìn)程之間的通信角色為:發(fā)送者和接受者
發(fā)送者:
a. 獲取消息隊列的ID(key或者msgid)
b. 將數(shù)據(jù)放入一個帶有標(biāo)識的消息結(jié)構(gòu)體,發(fā)送到消息隊列
接受者:
a. 獲取消息隊列的ID
b. 指定標(biāo)識的消息從消息隊列中讀出,然后進(jìn)一步后續(xù)處理 - 支持不同的進(jìn)程標(biāo)記不同的消息類型(1,2,3…),并由內(nèi)核態(tài)維護(hù)對應(yīng)消息類型的鏈表。
- 內(nèi)核態(tài)的0號消息類型維護(hù)了一個鏈表,用來保存按照時間順序加入的消息
編程接口
-
生成ipc對象的唯一標(biāo)識
key的接口
a. 頭文件<sys/ipc.h>
b. 函數(shù)聲明key_t ftok(const char *path, int id);
c. 參數(shù)描述
path需指定一個已經(jīng)存在的可訪問的文件
id為用戶可自由指定的id -
創(chuàng)建或者打開一個消息隊列,并獲取system V 消息隊列中消息的身份標(biāo)識
a. 頭文件<sys/types.h> <sys/ipc.h> <sys/msg.h>
b. 函數(shù)聲明int msgget (ket_t key, int msgflg)
c. 參數(shù)描述
key為ipc對象的唯一標(biāo)識,生成的消息身份標(biāo)識與該參數(shù)相關(guān)
msgflg當(dāng)該函數(shù)沒有搜索到系統(tǒng)中與key值對應(yīng)的消息隊列,則msgflg會指定IPC_CREAT,創(chuàng)建一個隊列,并返回消息標(biāo)識
d. 返回值:成功返回消息身份標(biāo)識,失敗返回-1 -
發(fā)送消息到消息隊列
a. 頭文件<sys/types.h> <sys/ipc.h> <sys/msg.h>
b. 函數(shù)聲明int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
c. 參數(shù)描述
msqid消息標(biāo)識,類似于文件描述符fd
msgp消息內(nèi)容指針
msgsz消息大小
msgflg當(dāng)出現(xiàn)消息隊列沒有足夠的可用空間時,可以通過設(shè)置msgflg為IPC_NOWAIT來讓發(fā)送函數(shù)不產(chǎn)生阻塞,返回失敗
d. 返回值 失敗返回-1,以及對應(yīng)失敗碼;成功則返回0 -
從消息隊列中接收消息
a. 頭文件<sys/types.h> <sys/ipc.h> <sys/msg.h>
b. 函數(shù)聲明ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
c. 參數(shù)描述
msqid消息標(biāo)識,類似于文件描述符fd
msgp消息內(nèi)容指針
msgsz消息大小,同時也是當(dāng)前接收的消息最大能夠接收的大小
msgflg當(dāng)出現(xiàn)實際的消息內(nèi)容大于設(shè)定的msgsz,可以通過MSG_NOERROR來將消息裁剪為msgsz大小進(jìn)行獲取,否則會返回失敗。而消息仍然存在于消息隊列。
msgtyp如果是0,則會讀取處于消息隊列的第一個消息;大于0,則會讀取對應(yīng)type處于消息隊列中的第一個消息;如果小于0,則會讀取type絕對值或者小于絕對值的消息隊列的第一個消息。
d. 返回值 失敗返回-1,成功返回對應(yīng)消息的大小 -
控制消息隊列的各個操作
a. 頭文件<sys/types.h> <sys/ipc.h> <sys/msg.h>
b. 函數(shù)聲明int msgctl(int msqid, int cmd, struct msqid_ds *buf);
c. 參數(shù)描述
msgqid消息標(biāo)識
cmd針對消息標(biāo)識的操作,合法的操作如下:IPC_STAT獲取msgqid的消息對象的信息,將各個屬性從內(nèi)核拷貝到一個臨時的數(shù)據(jù)結(jié)構(gòu)msgqid_ds類型的buf;調(diào)用者需要對消息隊列有讀權(quán)限IPC_SET自己可以通過臨時的msgqid_ds來設(shè)置內(nèi)核中消息的對應(yīng)msgqid_ds的屬性IPC_RMID立即移除消息隊列;當(dāng)前調(diào)用者需要擁有 消息隊列的所有者權(quán)限,或者高于所有者的權(quán)限(root)IPC_INFO返回消息隊列的參數(shù)限制
其他標(biāo)識可以通過
man msgctl來查看
代碼實例
消息隊列的發(fā)送和接收
發(fā)送端msg_snd.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define MSG_TYPE1 1
#define MSG_TYPE2 2 struct msgbuf
{long mtype;char mtext[100];
};int main()
{//當(dāng)多用戶的時候通過指定文件以及設(shè)置id來獲取唯一的key標(biāo)識//key_t key = ftok(".",100);key_t key = 12345; //個人使用的時候可以直接指定key//創(chuàng)建msg_qid的對象int msg_qid = msgget(key, IPC_CREAT | 0666);struct msgbuf msg;memset(&msg, 0 , sizeof(msg));//初始化消息類型以及消息內(nèi)容msg.mtype = MSG_TYPE2;strncpy(msg.mtext, "hello world" , 80);//發(fā)送消息到消息標(biāo)識的msg_qid IPC 對象中if( -1 == msgsnd(msg_qid,(void *)&msg,strlen(msg.mtext),0)) {printf("send msg failed\n");_exit(-1);}return 0;
}
編譯運行:
gcc msg_snd.c -o msg_snd
運行前查看系統(tǒng)消息隊列
ipcs -q
[root@node1 ~]# ipcs -q------ Message Queues --------
key msqid owner perms used-bytes messages
0x000004d2 0 root 666 0 0
運行后,可以看到我們發(fā)送了消息隊列的各個屬性信息。關(guān)于key值,它為我們設(shè)置的12345的16進(jìn)制數(shù)值
[root@node1 ~]# ./msg_snd
[root@node1 ~]# ipcs -q------ Message Queues --------
key msqid owner perms used-bytes messages
0x000004d2 0 root 666 0 0
0x00003039 65538 root 666 11 1
接收端msg_rcv.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define MSG_TYPE1 1
#define MSG_TYPE2 2 struct msgbuf
{long mtype;char mtext[100];
};int main()
{key_t key = 12345;int msg_qid = msgget(key, IPC_CREAT | 0666);struct msgbuf msg;memset(&msg, 0 , sizeof(msg));if (-1 == msgrcv(msg_qid,(void *)&msg,sizeof(msg.mtext),MSG_TYPE2,0)) {printf("receive msg failed\n");_exit(-1);}printf("%s\n",msg.mtext);//當(dāng)完成接收之后從消息隊列中刪除當(dāng)前消息//msgctl(msg_id,IPC_RMID,NULL);return 0;
}
編譯運行,可以看到已經(jīng)接手到了我們之前發(fā)送的內(nèi)容:
[root@node1 ~]# gcc msg_rcv.c -o msg_rcv
[root@node1 ~]# ./msg_rcv
hello world
查看消息隊列情況,消息隊列中的數(shù)據(jù)已經(jīng)被接收,所以在used-bytes和messages中看不到消息內(nèi)容了,但是沒有刪除該消息隊列,所以消息標(biāo)識仍然存在。我們可以在上述代碼中加入msgctl:
[root@node1 ~]# ipcs -q------ Message Queues --------
key msqid owner perms used-bytes messages
0x000004d2 0 root 666 0 0
0x00003039 65538 root 666 0 0
消息隊列中的消息對象的屬性控制
控制代碼msg_ctl.c
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
其中主要控制的是消息隊列一個數(shù)據(jù)結(jié)構(gòu),可以通過man msgctl查看 msqid_ds結(jié)構(gòu)體
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 inqueue (nonstandard) */msgqnum_t msg_qnum; /* Current number of messagesin queue */msglen_t msg_qbytes; /* Maximum number of bytesallowed in queue */pid_t msg_lspid; /* PID of last msgsnd(2) */pid_t msg_lrpid; /* PID of last msgrcv(2) */};
以下代碼為主要控制參數(shù)的代碼,通過msgctl的cmd參數(shù)進(jìn)程控制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int main()
{key_t key = 12345;int msg_id = msgget(key,IPC_CREAT|0666);struct msqid_ds info;//第一次先從已存在的12345的消息中獲取隊列狀態(tài)if (-1 == msgctl(msg_id,IPC_STAT,&info)) {printf("control msg failed\n");_exit(-1);}//打印各個狀態(tài)信息printf("uid :%d,gid:%d,cuid:%d,cgid:%d\n",\info.msg_perm.uid,info.msg_perm.gid,info.msg_perm.cuid,info.msg_perm.cgid);printf("mode:%o3o,cbytes:%lu,qnum:%lu,qbytes:%lu\n",\info.msg_perm.mode & 0777,info.__msg_cbytes,info.msg_qnum,info.msg_qbytes);//嘗試設(shè)置消息隊列允許的最大字節(jié)內(nèi)容info.msg_qbytes = 16000;//通過cmd為IPS_SET的標(biāo)記進(jìn)行設(shè)置if (-1 == msgctl(msg_id, IPC_SET, &info)) {printf("ipc_set failed\n");_exit(-1);}if (-1 == msgctl(msg_id, IPC_STAT, &info)) {printf("ipc_stat failed\n");_exit(-1);}printf("mode:%o3o,cbytes:%lu,qnum:%lu,qbytes:%lu\n",\info.msg_perm.mode & 0777,info.__msg_cbytes,info.msg_qnum,info.msg_qbytes);return 0;
}
輸出如下,可以看到我們控制的隊列允許的最大字節(jié)內(nèi)容msg_qbytes已經(jīng)設(shè)置進(jìn)去:
[root@node1 ~]# ./msg_ctl
uid :0,gid:0,cuid:0,cgid:0
mode:6663o,cbytes:11,qnum:1,qbytes:16000
mode:6663o,cbytes:11,qnum:1,qbytes:16000
總結(jié)
以上是生活随笔為你收集整理的linux进程间通信:system V消息队列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux进程间通信:FIFO实现进程间
- 下一篇: 一般封阳台窗户多少钱