msgsnd(2) - Linux man page
名称
msgrcv, msgsnd - message operations
概要
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
描述
msgsnd() 和 msgrcv() 系统调用分别用于向消息队列发送消息和从消息队列接收消息。调用进程必须对消息队列具有写权限才能发送消息,并具有读权限才能接收消息。
msgp 参数是指向调用者定义的以下通用形式结构的指针
-
struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ }; - mtext 字段是一个数组(或其他结构),其大小由非负整数值 msgsz 指定。允许零长度的消息(即,没有 mtext 字段)。mtype 字段必须具有严格正整数值。此值可供接收进程用于消息选择(请参阅 msgrcv() 下面的描述)。
msgsnd()
- msgsnd() 系统调用将指向 msgp 的消息的副本附加到标识符为 msqid 的消息队列中。
如果队列中有足够的空间,msgsnd() 会立即成功。(队列容量由与消息队列关联的数据结构中的 msg_qbytes 字段定义。在创建队列期间,该字段初始化为 MSGMNB 字节,但可以使用 msgctl(2) 修改此限制。)如果队列中没有足够的空间,则 msgsnd() 的默认行为是阻塞,直到有空间可用。如果 msgflg 中指定了 IPC_NOWAIT,则调用将失败并返回错误 EAGAIN。
阻塞的 msgsnd() 调用也可能在以下情况下失败:
- *
队列被删除,在这种情况下,系统调用将失败,errno 设置为 EIDRM;或者
*
捕获到信号,在这种情况下,系统调用将失败,errno 设置为 EINTR;请参阅 signal(7)。(msgsnd() 不会自动在被信号处理程序中断后重新启动,无论建立信号处理程序时 SA_RESTART 标志的设置如何。)
- 成功完成时,消息队列数据结构将更新如下
- msg_lspid 设置为调用进程的进程 ID。
msg_qnum 递增 1。
msg_stime 设置为当前时间。
msgrcv()
- msgrcv() 系统调用从由 msqid 指定的队列中删除一条消息,并将其放入指向 msgp 的缓冲区中。
参数 msgsz 指定指向 msgp 参数的结构的 mtext 成员的最大字节大小。如果消息文本的长度大于 msgsz,则行为取决于是否在 msgflg 中指定了 MSG_NOERROR。如果指定了 MSG_NOERROR,则消息文本将被截断(截断的部分将丢失);如果未指定 MSG_NOERROR,则消息不会从队列中删除,并且系统调用将失败,返回 -1,errno 设置为 E2BIG。
参数 msgtyp 指定请求的消息类型如下
- *
如果 msgtyp 为 0,则读取队列中的第一条消息。
*
如果 msgtyp 大于 0,则读取队列中类型为 msgtyp 的第一条消息,除非在 msgflg 中指定了 MSG_EXCEPT,在这种情况下,将读取队列中类型不等于 msgtyp 的第一条消息。
*
如果 msgtyp 小于 0,则将读取队列中类型小于或等于 msgtyp 绝对值的最低消息。
- msgflg 参数是一个通过 OR 运算零个或多个以下标志构造的位掩码
- IPC_NOWAIT
- 如果队列中没有请求类型的消息,则立即返回。系统调用将失败,errno 设置为 ENOMSG。
- MSG_EXCEPT
- 与大于 0 的 msgtyp 一起使用,以读取队列中消息类型与 msgtyp 不同的第一条消息。
- MSG_NOERROR
- 如果消息文本长于 msgsz 字节,则截断消息文本。
- 如果没有可用的请求类型的消息,并且未在 msgflg 中指定 IPC_NOWAIT,则调用进程将阻塞,直到以下条件之一发生
- *
所需类型的消息被放置在队列中。
*
消息队列从系统中删除。在这种情况下,系统调用将失败,errno 设置为 EIDRM。
*
调用进程捕获到信号。在这种情况下,系统调用将失败,errno 设置为 EINTR。(msgrcv() 不会自动在被信号处理程序中断后重新启动,无论建立信号处理程序时 SA_RESTART 标志的设置如何。)
- 成功完成时,消息队列数据结构将更新如下
- msg_lrpid 设置为调用进程的进程 ID。
msg_qnum 递减 1。
msg_rtime 设置为当前时间。
返回值
在失败时,这两个函数都返回 -1,errno 指示错误,否则 msgsnd() 返回 0,msgrcv() 返回实际复制到 mtext 数组中的字节数。
错误
当 msgsnd() 失败时,errno 将设置为以下值之一
- EACCES
调用进程对消息队列没有写权限,并且没有 CAP_IPC_OWNER 功能。
EAGAIN
由于队列的 msg_qbytes 限制而无法发送消息,并且在 msgflg 中指定了 IPC_NOWAIT。
EFAULT
指向 msgp 的地址不可访问。
EIDRM
消息队列已被删除。
EINTR
在等待满消息队列条件时,进程捕获到信号。
EINVAL
无效的 msqid 值,或非正的 mtype 值,或无效的 msgsz 值(小于 0 或大于系统值 MSGMAX)。
ENOMEM
系统没有足够的内存来复制指向 msgp 的消息。
- 当 msgrcv() 失败时,errno 将设置为以下值之一
- E2BIG
消息文本长度大于 msgsz,并且未在 msgflg 中指定 MSG_NOERROR。
EACCES
调用进程对消息队列没有读权限,并且没有 CAP_IPC_OWNER 功能。
EAGAIN
队列中没有可用消息,并且在 msgflg 中指定了 IPC_NOWAIT。
EFAULT
指向 msgp 的地址不可访问。
EIDRM
在进程等待接收消息时,消息队列被删除。
EINTR
在进程等待接收消息时,进程捕获到信号;请参阅 signal(7)。
EINVAL
msgqid 无效,或 msgsz 小于 0。
ENOMSG
在 msgflg 中指定了 IPC_NOWAIT,并且消息队列上不存在请求类型的消息。
符合
SVr4, POSIX.1-2001。
说明
Linux 或任何 POSIX 版本不需要包含 <sys/types.h> 和 <sys/ipc.h>。然而,一些旧的实现要求包含这些头文件,SVID 也记录了它们的包含。打算移植到此类旧系统的应用程序可能需要包含这些头文件。
在 libc4、libc5、glibc 2.0、glibc 2.1 中,msgp 参数声明为 struct msgbuf *。在 glibc 2.2 及更高版本中,它声明为 void *,如 SUSv2 和 SUSv3 所要求。
以下消息队列资源限制会影响 msgsnd() 调用
- MSGMAX
消息文本的最大大小:8192 字节(在 Linux 上,可以通过 /proc/sys/kernel/msgmax 读取和修改此限制)。
MSGMNB
消息队列的最大字节大小的默认值:16384 字节(在 Linux 上,可以通过 /proc/sys/kernel/msgmnb 读取和修改此限制)。超级用户可以通过 msgctl(2) 系统调用将消息队列的大小增加到超过 MSGMNB。
- 实现对系统范围内消息头数的最大数量 (MSGTQL) 和消息池的最大字节大小 (MSGPOOL) 没有内在限制。
参见
msgctl(2), msgget(2), capabilities(7), mq_overview(7), svipc(7)