ipc 消息队列message queue

本文详细介绍了系统V消息队列的工作原理和技术细节。重点讲述了消息队列如何通过内核中的数据结构进行管理,以及消息队列头所包含的重要信息。此外还提供了访问和设置这些信息的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面博客对进程通信消息队列讲述的很清晰.

1.http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/

2.http://blog.youkuaiyun.com/anonymalias/article/details/9829417


  1. 系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。
  2. 消息队列就是一个消息的链表。每个消息队列都有一个队列头,用结构struct msg_queue来描述(参见 附录 2)。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。
  3. 下图说明了内核与消息队列是怎样建立起联系的: 
    其中:struct ipc_ids msg_ids是内核中记录消息队列的全局数据结构;struct msg_queue是每个消息队列的队列头。

从上图可以看出,全局数据结构 struct ipc_ids msg_ids 可以访问到每个消息队列头的第一个成员:struct kern_ipc_perm;而每个struct kern_ipc_perm能够与具体的消息队列对应起来是因为在该结构中,有一个key_t类型成员key,而key则唯一确定一个消息队列。kern_ipc_perm结构如下:

struct kern_ipc_perm{   //内核中记录消息队列的全局数据结构msg_ids能够访问到该结构;
            key_t   key;    //该键值则唯一对应一个消息队列
            uid_t   uid;
            gid_t   gid;
uid_t   cuid;
gid_t   cgid;
mode_t  mode;
unsigned long seq;
}
对其中的操作和semphore ,shared memory 一样
### Linux IPC 消息队列使用教程 #### 创建消息队列 在Linux环境中,`msgget` 函数用于创建一个新的消息队列或获取已存在的消息队列的标识符。此函数接受两个参数:一个是键值(通常由 `ftok()` 生成),另一个是由标志位组成的整数,指示操作模式。 ```c #include <sys/msg.h> key_t key = ftok("/path/to/file", project_id); int msgid = msgget(key, IPC_CREAT | 0666); // 创建新队列并赋予读写权限 ``` 上述代码片段展示了如何利用文件路径和项目ID来生成唯一的键值,并调用 `msgget` 来尝试创建新的消息队列或将现有队列打开以便后续访问[^1]。 #### 发送消息至队列 为了向消息队列发送数据包,程序需先定义结构体表示要传输的消息格式,之后再调用 `msgsnd` 函数执行实际传送动作: ```c struct my_msgbuf { long mtype; char mtext[20]; }; // 填充消息内容... my_msgbuf sbuf; sbuf.mtype = 1L; /* 类型 */ strcpy(sbuf.mtext, "Hello"); if (msgsnd(msgid, &sbuf, sizeof(sbuf), 0) == -1) perror("msgsnd"); ``` 这里展示了一个简单的例子,其中包含了一条带有特定类型的短字符串信息被放入指定的消息队列中[^3]。 #### 接收来自队列的消息 接收端同样需要声明相同布局的消息缓冲区结构体,接着通过 `msgrcv` 函数从目标队列里提取匹配类型的信息项: ```c struct my_msgbuf rbuf; size_t buf_length = sizeof(rbuf); /* 阻塞直到接收到mtype等于1的消息 */ ssize_t bytes_read = msgrcv(msgid, &rbuf, buf_length - sizeof(long), 1L, 0); if(bytes_read != -1){ printf("Received message: %.*s\n", (int)bytes_read, rbuf.mtext); } else { perror("msgrcv failed"); } ``` 这段代码说明了怎样等待并捕获符合预期条件的第一条可用记录,同时打印其有效载荷部分的内容。 #### 设置消息队列属性 有时可能还需要调整已经建立好的队列特性,比如更改所有权或者存取控制列表ACL等安全策略;这可以通过 `msgctl` 结合命令常量 `IPC_SET` 完成配置更新工作: ```c struct msqid_ds qinfo; memset(&qinfo, '\0', sizeof(qinfo)); qinfo.msg_perm.uid = getuid(); qinfo.msg_perm.gid = getgid(); qinfo.msg_qbytes = 1024 * 1024; // 扩展最大字节数限制 if (-1 == msgctl(msqid, IPC_SET, &qinfo)) perror("Failed to set queue parameters."); else puts("Successfully updated the message queue settings."); ``` 以上实例演示了修改当前用户的UID/GID以及扩大存储容量上限的方法[^4]。 #### 销毁不再使用的队列 当应用程序结束运行前应当清理掉所占用的一切资源,对于临时性的消息通道而言意味着销毁它本身以免造成系统内核对象残留问题: ```c if(-1 == msgctl(msgid, IPC_RMID, NULL)) fprintf(stderr,"Error removing message queue.\n"); else printf("Message queue removed successfully.\n"); ``` 该段落提供了关于移除无用队列的标准做法,即传入特殊指令 `IPC_RMID` 给 `msgctl` 调用以实现目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值