在APUE 14.7节对消息队列的讲解中,最后一段说“我们得出的结论是:在新的应用程序中不应当再使用它们。”
虽然在新的应用程序中不应该再使用消息队列,我也没有怎么使用过System V IPC总觉得在UNIX/Linux编程中少了什么,也许学习一下System V IPC对我的自信心会有相当大的帮助,从此我也敢讲我知道如何使用IPC了。
先把各个函数原形列出。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflag);
int msgsnd(int msgid, struct msgbuf *msgp, size_t msgsz, int msgflag);
ssize_t msgrcv(int msgid, struct msgbuf *msgp, size_t msgsz, long msgtype, int msgflag);
int msgctl(int msgid, int cmd, struct msqid_ds *buf);
msgget()用来创建Message Queue(服务端)或者和一个已经建立的Message Queue连接(客户端)。key,指定用来生成message id的关键字,msgflag和open()的flags很相似,可用IPC_CREAT, IPC_EXECL, S_IRUSR等。
在服务端,可用IPC_PRIVATE(或者0)来指定key值,来生成一个新的Message Queue,或使用指定的key值(32位的无符号数),或者使用ftok()来生成一个key。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
在客户端,可以直接使用服务端生成的message id(通过某些途径传送,如文件,父子进程),也可以用msgget通过和服务端使用相同的key值来生成相同的message id,但不能使用IPC_PRIVATE(或者0),msgflag也不能使用IPC_CREAT。
Return Value: Sucess return value is the message id(non-negative integer), otherwise -1 return.
msgsnd()用来发送消息。
struct msgbuf {
long mtype;
char mtext[1];
};
msgsz的计算方法: msgsz = sizeof(msgbuf) - sizeof(long);
msgflag有一个标志:IPC_NOWAIT。当消息队列已满(可能是消息总数达到了限制值,也可能是队列中字节总数达到了限制值),立即出错返回,如果没有指定,则阻塞。
msgrcv()用来接收消息。msgtype用来指定读取的消息类型。msgtype == 0, 返回第一个消息; msgtype > 0, 返回消息类型为msgtype的消息;msgtype < 0, 返回队列中类型值小于msgtype的绝对值的消息集中最小的消息。
msgflag有两个值:MSG_NOERROR, IPC_NOWAIT。当MSG_NOERROR被指定的时候,若消息太长就被截断,否则返回错误;IPC_NOWAIT用于需要读取的消息不存在时则阻塞。
msgctl用于控制消息队列。cmd有三种值:IPC_STAT,IPC_SET,IPC_RMID。
IPC_STAT用于取出消息队列的 msqid_ds结构并保存到buf中。
IPC_SET用来把buf指向的msqid_ds,设置成消息队列的msqid_ds。只有四个值可以更改:msg_perm.uid, msg_perm.gid,msg_perm.mode, msg_qbytes。
IPC_RMID用来删除消息队列。
struct msqid_ds
{
struct ipc_perm msg_perm;
ulong msg_qbytes; //max of bytes of queue
...
};
struct ipc_perm
{
uid_t uid; //owner's effective user id
gid_t gid; //owner's effective group id
uid_t cuid; //creator's effective user id
gid_t cgid; //creator's effective group id
mode_t mode; //aclearcase/" target="_blank" >ccess modes
ulong seq; //slot usage sequence number
key_t key;
};