[TOC] 1. 概述 System V消息隊列使用消息隊列標識符標識,和Posix消息隊列一樣,發送消息和接收消息的線程(進程)是相互獨立、互不依賴的。 對於系統中的每個消息隊列,內核維護一個定義在sys/msg.h頭文件中的結構,其中帶註釋的是我們需要關註的成員變數。 2. 消息隊列API ms ...
目錄
1. 概述
System V消息隊列使用消息隊列標識符標識,和Posix消息隊列一樣,發送消息和接收消息的線程(進程)是相互獨立、互不依賴的。
對於系統中的每個消息隊列,內核維護一個定義在sys/msg.h頭文件中的結構,其中帶註釋的是我們需要關註的成員變數。
struct msqid_ds
{
struct ipc_perm msg_perm;
struct msg *msg_first; //指向隊列中第一條消息
struct msg *msg_last; //指向隊列中最後一條消息
msglen_t msg_cbytes; //消息隊列當前第幾個位元組
msgqnum_t msg_qnum; //消息隊列當前第幾條消息
msglen_t msg_qbytes; //消息隊列允許的最大位元組數,僅針對消息數據,不包括與每個消息關聯的長整型消息類型
pid_t msg_lspid;
pid_t msg_lrpid;
time_t msg_stime;a
time_t msg_rtime;
time_t msg_ctime;
};
2. 消息隊列API
msgget
msgget用於創建一個新的消息隊列或訪問一個已存在的消息隊列,參數key和oflag的含義及使用方法和semget一樣,不再贅述。
//成功返回消息隊列標識符,失敗返回-1
int msgget(key_t key, int oflag);
msgsnd
msgsnd用於向消息隊列中添加一條消息。
//成功返回0,失敗返回-1
int msgsnd(int msqid, const void *ptr, size_t length, int flag);
參數說明:
- msqid是msgget返回的標識符
- ptr是一個由應用程式按如下模板定義的struct sembuf結構指針,只要保證第一個成員變數是long type即可,其後的數據部分可根據需要任意擴展
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
- length是待發送消息的長度,即消息類型之後的用戶自定義數據的長度,該長度可以是0
- flag可以是0或者IPC_NOWAIT,一般設為0
msgrcv
msgrcv用於從消息隊列中取出一條消息。
//成功返回實際讀入緩衝區的數據長度,失敗返回-1
int msgrcv(int msqid, void *ptr, size_t length, long type, int flag);
參數說明:
- msqid是msgget返回的標識符
- ptr指向數據接收緩衝區,它應該和msgsnd的ptr具有同樣的struct sembuf結構
- length為緩衝區大小
- type用於指定希望從消息隊列中讀出什麼樣的消息
- flag可以是0、IPC_NOWAIT或MSG_NOERROR,一般設為0
msgrcv第四個參數type用於指定希望從消息隊列中讀出什麼樣的消息,假設有消息隊列中有三條消息:
- 第一條消息的類型為100,長度為1
- 第二條消息的類型為200,長度為2
- 第二條消息的類型為300,長度為3
那麼:
- type = 0:返回隊列中第一個消息
- type > 0:返回消息類型等於type的第一個消息
- type < 0:返回消息類型 <= abs(type)的消息中類型值最小的第一個消息
msgctl
msgctl提供在一個消息隊列上的各種控制操作。
//成功返回0,失敗返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl支持三個cmd命令:
- IPC_RMID:從系統中刪除由msqid指定的消息隊列,此時第三個參數被忽略,設為NULL即可
- IPC_STAT:通過buf參數返回由msqid指定消息隊列對應的msqid_ds結構
- IPC_SET:通過buf參數返回由msqid指定消息隊列對應的msqid_ds結構,但僅設置以下4個成員:msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_perm.qbytes
3. 簡單的程式
代碼實現
common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define FTOK_FILE "/home/delphi/ftok.file"
#define FTOK_ID 1
#define MSG_RD_PERMISSION 0444
#define MSG_WR_PERMISSION 0222
#define MSG_RW_PERMISSION (MSG_RD_PERMISSION | MSG_WR_PERMISSION)
#define MAX_MSG_LEN (8192 + sizeof(long))
struct msgbuf
{
long type;
char *data;
};
#endif
msgcreate.c
#include "common.h"
int main()
{
key_t key = ftok(FTOK_FILE, FTOK_ID);
int oflag = IPC_CREAT | MSG_RW_PERMISSION;
int msgid = msgget(key, oflag);
if (msgid >= 0)
{
printf("msgget create success, msgid = %d\n", msgid);
}
return 0;
}
msgsnd.c
#include "common.h"
int main(int argc, char **argv)
{
int msgid;
int msglen;
long msgtype;
struct msgbuf *msg;
msgid = msgget(ftok(FTOK_FILE, FTOK_ID), MSG_WR_PERMISSION);
msglen = atoi(argv[1]);
msgtype = atol(argv[2]);
msg = (struct msgbuf *)calloc(sizeof(long) + msglen, sizeof(char));
msg->type = msgtype;
msgsnd(msgid, msg, msglen, 0);
return 0;
}
msgrcv.c
#include "common.h"
int main(int argc, char **argv)
{
int msgid;
int rcvlen;
long msgtype;
struct msgbuf *msg;
msgid = msgget(ftok(FTOK_FILE, FTOK_ID), MSG_RD_PERMISSION);
msgtype = atol(argv[1]);
msg = (struct msgbuf *)calloc(MAX_MSG_LEN, 1);
rcvlen = msgrcv(msgid, msg, MAX_MSG_LEN, msgtype, 0);
printf("read %d bytes, type = %ld\n", rcvlen, msg->type);
return 0;
}
msgrmid.c
#include "common.h"
int main(int argc, char **argv)
{
int msgid = msgget(ftok(FTOK_FILE, FTOK_ID), 0);
msgctl(msgid, IPC_RMID, 0);
return 0;
}