消息队列是由内核维护的消息链表。每个消息链表有一个名字和标识id,名字在进程之间通用,标识id被内核使用,名字也称为key,被用户使用,一个消息队列有一个公共的key,这个公共的key是大家都知道的,但是为了避免冲突,可以使用
key_t ftok(const char *path, int id);
来获得一个key。第一个参数是文件路径,第二个参数是项目id。这样所有的进程都只引用同一个文件和相同的项目id就可以避免key的冲突。
int msgget(key_t key, int flags);
获得一个消息队列,这里的获得包括创建(根据flags指定的值确定)。msgget得到队列标识符,key指定队列公共key,key可以取IPC_PRIVATE, 用来标识这个key的值不重要,因为我是私自用的。
flags可取下面的值的或:
flag | 作用 |
---|---|
IPC_CREAT | 当key对应的信号量不存在时创建它 |
IPC_EXCL | 当key对应的信号量已经存在时,返回出错 |
mode | 类似于0660的权限,如果不设置其它进程可能没有权限访问 |
int msgctl(int id, int cmd, struct msqid_ds *buf);
对id对应的消息队列进行cmd指定的操作,而有一部分操作需要buf。
cmd | 说明 |
---|---|
IPC_STAT | 获取该队列的信息存到buf中 |
IPC_SET | 设置队列信息中的uid, gid, mode, qbytes为buf中的值 |
IPC_RMID | 删除队列,只要一删除,立即生效,其它正在对该队列的动作立即失败返回。 |
struct msqid_ds
{
struct ipc_perm msg_perm; //permission
msgqnum_t msg_qnum; //消息的个数
msglen_t msg_qbytes; //同时在队列中的最大长度
pid_t msg_lspid;
pid_t msg_lrpid;
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
};
int msgsnd(int msgqit, const char *ptr, size_t nbytes, int flag);
发送一个消息,一个消息包括一个消息类型和数据,ptr指向一个长整形,长整形之后跟着数据,nbytes标至数据长度,flags可以被指定为IPC_NOWAIT.
ptr可能是这样的:
struct msg
{
long mtype;
char mtext[512];
};
这个时候,nbytes为512, 函数成功返回0, 失败返回-1.
flags IPC_NOWAiT.
ssize_t msgrcv(int id, void *ptr, size_t nbytes, long type, int flag);
ptr和snd相同,nbytes标识数据长度,type用来标志要接收的消息类型:
type | 说明 |
---|---|
>0 | 接收type类型的消息中最早的一个。 |
=0 | 接收所有消息中的最早的一个。 |
< 0 | 接收小于type绝对值中类型值最小的那个。 |
flag同样可取IPC_NOWAIT.
经过验证,id是内核中唯一的值,和文件描述符不同,内核中用的哪个消息队列标识符程序中就用哪个,所有的进程都用一个标识符,所以,只要知道内核所用标识符的id就不用msgget都可以了,但一般没法知道,只能通过提前指定或者通过ftok来转换。