进程间通信之System V消息队列(一)-msgget,msgctl

本篇文章总结学习System V消息队列的相关知识,主要包括以下几方面内容:消息列队基本概念,IPC对象数据结构,消息队列结构,消息队列在内核中的表示,消息队列函数等。

1.消息队列

(1)消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法。(从一个进程向另一个进程发送数据还可以使用管道,二者区别是管道是基于字节流的)

(2)每个数据块都被认为是一个类型,接收者进程接收的数据块可以有不同的类型之。

(3)消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。
可以通过以下命令查看:
cat /proc/sys/kernel/msgmax
cat /proc/sys/kernel/msgmnb
cat /porc/sys/kernel/msgmni

2.IPC对象数据结构

内核为每个IPC对象维护一个数据结构:ipc_perm

3.消息队列结构

msqid_ds

1)其中,第一个字段是前面提及的IPC对象的数据结构,这与共享内存和信号量是一样的。接下来的字段才是消息队列所特有的字段。
2)msg_qbytes表示消息队列所允许的最大字节数,即MSGMNB。

4.消息队列在内核中的表示

消息队列内核表示

1)以链表的方式连接每一个消息。

5.消息队列函数

其中,
msgget:创建或打开一个消息队列。
msgctl:用来控制消息队列,比如改变一个消息队列的权限,删除一个消息队列。
msgsnd:往消息队列发送一条消息。
msgrcv:从消息队列中接收一条消息。

(1)msgget函数

  • 功能:用来创建和访问一个消息队列
  • 原型:int msgget(key_t key, int msgflg);
  • 参数:
    • key:某个消息队列的名字(key与msqid是不同的)
    • msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
  • 返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1

考虑如下示例:

1)其中,若不指定IPC_CREAT将创建失败出现如下错误提示:
msgget:No such file or directory
2)这种情况类似于open函数,若open创建一个文件的时候没有指定O_CREAT,将创建失败。
3)所以,在该消息队列不存在的前提下,去创建一个消息队列应该指定IPC_CREAT。此外,若同时指定IPC_CREAT | EXECL,并且要创建的消息队列已经存在了,那么将会创建失败,并出现如下错误提示:
msgget:File exists

4)若将key指定为IPC_PRIVATE,则无论该消息队列是否已经存在,都会再创建一个消息队列(key相同,但msqid不同,可ipcs命令查看)

5)若要打开一个已存在的消息队列,可以不指定第二个参数msgflg:
msgid = msgget(1234, 0);

用图直观的总结如下:msgget

附:
查看ipc命令:ipcs
删除消息队列:ipcrm -q [msqid]

(2)msgctl函数

  • 功能:消息队列的控制函数
  • 原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • 参数:
    • msqid:由msgget函数返回的消息队列标识码
    • cmd:是将要采取的动作(有三个可取值)
  • 返回值:成功返回0;失败返回-1

其中cmd的三个取值如下:

  • IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值,即把消息队列的状态保存到IPC结构体msqid_ds中
  • IPC_SET:在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
  • IPC_RMID:删除消息队列

1)考虑如下示例:使用IPC_RMID删除消息队列

2)如下示例:使用IPC_STAT获取消息队列的权限(也可获取msqid_ds中的其他信息)

输出:

3)使用IPC_SET改变消息队列的权限:

输出:

其中,调用了两次msgctl函数:首先调用msgctl函数获取消息队列的状态至msqid_ds结构buf中,然后修改mode的值;再次调用msgctl函数设置修改后的buf为消息队列的新状态。

发表评论

电子邮件地址不会被公开。 必填项已用*标注