消息队列(MSG)
1. 基本概念
Linux 消息队列是 Linux 系统中的一种进程间通信机制。它允许多个进程向一个消息队列中写入消息,或者从消息队列中读取消息。
消息队列是一种先进先出(FIFO)的数据结构,可以存储任意类型的消息。消息队列有两个指针:一个指向队列头,一个指向队列尾。写入消息的进程会向队列尾写入消息,而读取消息的进程则会从队列头读取消息。
消息队列可以用于进程间的同步和通信。例如,可以通过消息队列来实现进程间的异步通信,也可以用来实现进程间的同步。消息队列通常用 于实现多线程应用程序,能够有效地提高应用程序的性能和可维护性。
Linux 消息队列的基本操作包括创建、打开、关闭、发送和接收消息等,使用方法一般是:
- 发送者:
- 获取消息队列的ID。
- 将数据放入一个附带有标识的特殊的结构体,发送给消息队列。
- 接收者:
- 获取消息队列的ID。
- 将指定标识的消息读出。
当发送者和接收者都不再使用消息队列时,需要及时删除它以释放系统资源。
2. 消息队列API
2.1 获取消息队列ID
msgget()
用于获取一个消息队列的描述符。该函数的原型如下:
int msgget(key_t key, int msgflg);
该函数接受两个参数:
key
:消息队列的键值。- xxxxxxxxxx1 1int shmget(key_t key, size_t size, int shmflg);jsx showLineNumbers
如果函数执行成功,则返回一个消息队列的描述符。否则,返回
-1
。
msgget()
函数用于获取一个消息队列的描述符。它能够通过消息队列的键值来查找消息队列,并返回一个用于操作消息队列的描述符。例如,可以使用 msgget()
函数来获取一个消息队列的描述符,然后通过该描述符来向消息队列发送消息。
2.2 发送消息
msgsnd()
用于向消息队列中写入消息。该函数的原型如下:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
该函数接受四个参数:
msqid
:消息队列的描述符。msgp
:指向要写入消息队列的消息缓冲区的指针。msgsz
:要写入消息队列的消息的大小。msgflg
:控制写入消息队列的方式的标志。如果函数执行成功,则返回 0。否则,返回一个非 0 值。
msgsnd()
函数用于向消息队列中写入消息。它能够将一个消息写入指定的消息队列,并在写入成功时返回。例如,可以使用 msgget()
函数获取消息队列的描述符,然后使用 msgsnd()
函数向该消息队列中写入消息。
- 选项msgflg是一个位屏蔽字,因此IPC_CREAT、IPC_EXCL和权限mode可以用位或的方式叠加起来,比如:
msgget(key, IPC_CREAT\0666);
表示如果key对应的消息队列不存在就创建,且权限指定为 0666,若已存在则直接获取 ID。 - 权限只有读和写,执行权限是无效的,例如0777跟0666是等价的。
- 当key被指定为IPC_PRVATE 时,系统会自动产生一个未用的 key来对应一个新的消息队列对象。一般用于线程间通信。
2.3 接收消息
msgrcv()
是 Linux 系统中的一个函数,用于从消息队列中读取消息。该函数的原型如下:
int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
该函数接受五个参数:
msqid
:消息队列的描述符。msgp
:指向要用于存储读取到的消息的 缓冲区的指针。msgsz
:要读取的消息的大小。msgtyp
:要读取的消息的类型。msgflg
:控制读取消息队列的方式的标志。如果函数执行成功,则返回实际读取到的消息的大小。否则,返回一个负值。
msgrcv()
函数用于从消息队列中读取消息。它能够从指定的消息队列中读取一条消息,并在读取成功时返回。例如,可以使用 msgget()
函数获取消息队列的描述符,然后使用 msgrcv()
函数从该消息队列中读取消息。
使用这两个收、发消息函数需要注意以下几点:
- 发送消息时,消息必须被组织成以下形式:
struct msgbuf {
long mtype;//消息的标识
char mtext[1];//消息的正文
}
也就是说:发送出去的消息必须以一个long型数据打头,作为该消息的标识,后面的数据则没有要求。
- 消息的标识可以是任意长整型数值,但不能是OL。
- 参数
msgsz
是消息中正文的大小,不包含消息的标识。
2.4 设置或获取消息队列属性
msgctl()
是 Linux 系统中的一个函数,用于控制消息队列。该函数的原型如下:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
该函数接受三个参数:
msqid
:消息队列的描述符。cmd
:指定要进行的操作的类型。
- IPC_STAT:获取该MSG的信息,储存在结构体 msqid_ds 中。
- IPC_SET:设置该MSG的信息,储存在结构体 msqid_ds。
- IPC_RMID: 立即删除该MSG,并且唤醒所有阻塞在该MSG上的进程,同时忽略第三个参数。
- IPC_INFO:获得关于当前系统中 MSG的限制值信息。
- MSG_INFO:获得关于当前系统中MSG的相关资源消耗信息。
- MSG_STAT:同IPC_STAT,但 msgid为该消息队列在内核中记录所有消息队列信息的数组的下标,因此通过迭代所有的下标可以获得系统中所有消息队列的相关信息
buf
:指向用于存储消息队列信息的结构体的指针。如果函数执行成功,则返回 0。否则,返回一个非 0 值。
msgctl()
函数用于控制消息队列。它能够对指定的消息队列执行各种操作,例如,查询消息队列信息、更改消息队列的标志、删除消息队列等。该函数的行为取决于 cmd
参数的值。例如,如果将 cmd
设为 IPC_STAT
,则 msgctl()
函数会将指定消息队列的信息存储到 buf
所指向的结构体中。