7. msgget - 获取消息队列标识符 Link to heading
函数介绍 Link to heading
msgget
系统调用用于创建或访问System V消息队列。消息队列是一种进程间通信机制,允许进程通过发送和接收消息来交换数据,消息按先进先出(FIFO)的顺序处理。
函数原型 Link to heading
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能 Link to heading
创建新的消息队列或获取现有消息队列的标识符。
参数 Link to heading
key_t key
: 消息队列的键值IPC_PRIVATE
: 创建私有消息队列- 正整数: 通过
ftok()
函数生成的键值
int msgflg
: 标志位组合IPC_CREAT
: 如果消息队列不存在则创建IPC_EXCL
: 与IPC_CREAT配合使用,如果已存在则失败- 权限位: 如0666(读写权限)
返回值 Link to heading
- 成功时返回消息队列的标识符(非负整数)
- 失败时返回-1,并设置errno:
EACCES
: 权限不足EEXIST
: 消息队列已存在(使用IPC_EXCL时)EINVAL
: 参数无效ENOENT
: 消息队列不存在且未指定IPC_CREATENOSPC
: 系统消息队列数量已达上限
相似函数 Link to heading
msgsnd()
: 发送消息到消息队列msgrcv()
: 从消息队列接收消息msgctl()
: 控制消息队列ftok()
: 生成System V IPC键值
示例代码 Link to heading
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
// 消息结构体
struct msg_buffer {
long msg_type; // 消息类型,必须为正整数
char msg_text[100]; // 消息内容
};
int main() {
key_t key;
int msgid;
printf("=== Msgget函数示例 ===\n");
// 示例1: 使用IPC_PRIVATE创建私有消息队列
printf("\n示例1: 创建私有消息队列\n");
msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
if (msgid == -1) {
perror("创建私有消息队列失败");
exit(EXIT_FAILURE);
}
printf(" 成功创建私有消息队列,标识符: %d\n", msgid);
// 删除消息队列
if (msgctl(msgid, IPC_RMID, NULL) == -1) {
perror("删除消息队列失败");
} else {
printf(" 成功删除消息队列\n");
}
// 示例2: 使用ftok生成键值创建消息队列
printf("\n示例2: 使用ftok创建消息队列\n");
// 生成键值
key = ftok(".", 'e');
if (key == -1) {
perror("ftok失败");
exit(EXIT_FAILURE);
}
printf(" 生成的键值: %d\n", key);
// 创建消息队列
msgid = msgget(key, 0666 | IPC_CREAT);
if (msgid == -1) {
perror("创建消息队列失败");
exit(EXIT_FAILURE);
}
printf(" 成功创建消息队列,标识符: %d\n", msgid);
// 示例3: 尝试创建已存在的消息队列
printf("\n示例3: 尝试重复创建消息队列\n");
int msgid2 = msgget(key, 0666 | IPC_CREAT | IPC_EXCL);
if (msgid2 == -1) {
if (errno == EEXIST) {
printf(" 消息队列已存在\n");
} else {
perror(" msgget失败");
}
} else {
printf(" 意外创建了新的消息队列: %d\n", msgid2);
// 清理
msgctl(msgid2, IPC_RMID, NULL);
}
// 示例4: 获取已存在的消息队列
printf("\n示例4: 获取已存在的消息队列\n");
int msgid3 = msgget(key, 0666);
if (msgid3 == -1) {
perror("获取消息队列失败");
} else {
printf(" 成功获取消息队列,标识符: %d\n", msgid3);
// 验证是否为同一个消息队列
if (msgid3 == msgid) {
printf(" 确认为同一个消息队列\n");
}
}
// 示例5: 错误处理演示
printf("\n示例5: 错误处理\n");
// 尝试访问不存在的消息队列(不创建)
int msgid4 = msgget(12345, 0666);
if (msgid4 == -1) {
if (errno == ENOENT) {
printf(" 消息队列不存在: %s\n", strerror(errno));
} else {
perror(" 其他错误");
}
}
// 示例6: 权限测试
printf("\n示例6: 权限测试\n");
// 创建一个只读的消息队列
key = ftok(".", 'f');
if (key != -1) {
int readonly_msgid = msgget(key, 0444 | IPC_CREAT);
if (readonly_msgid != -1) {
printf(" 成功创建只读消息队列: %d\n", readonly_msgid);
// 尝试获取写权限(应该失败)
int write_msgid = msgget(key, 0222);
if (write_msgid == -1) {
printf(" 获取写权限失败: %s\n", strerror(errno));
}
// 清理
msgctl(readonly_msgid, IPC_RMID, NULL);
}
}
// 清理:删除创建的消息队列
printf("\n清理资源...\n");
if (msgctl(msgid, IPC_RMID, NULL) == -1) {
perror("清理消息队列失败");
} else {
printf(" 成功清理消息队列\n");
}
return 0;
}