linux IPC 消息队列
消息队列函数原型
在建立IPC通讯时(如消息队列,共享内存)必须建立一个ID值。通常情况下,这个ID值由ftok函数得到
#inlcude <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id);
返回值:成功返回键值,失败-1。
pathname:现有文件路径
proj_id:低8位整型
假如要确保key_t值不变,要目确保ftok的文档不被删除 ,要么不用ftok,指定一个固定的key_t值。
在linux下通过ftok()产生ipc键值、且ftok()与配置文件相关,则在更改了配置文件后必须将应用重起。否则将导致不可预料的后果!
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/ipc.h> 4 5 int main() 6 { 7 printf("key=%0x\n", ftok("aaa.txt", 1000)); 8 return 0; 9 }
打开一个现有队列或创建一个新队列:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgget(key_t key, int msgflg);
返回值:成功消息队列ID,失败-1
key:函数ftok返回值或IPC_PRIVATE(适合用在有亲缘关系的进程中)
msgflg: 消息队列的简历标志和存取权限
IPC_CREAT如果内核中没有此队列,则创建它。 IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。 如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。 返回说明: 成功执行时,返回消息队列标识值。失败返回-1,errno被设为以下的某个值 ,有时也会返回0,这个时候也是可以正常使用的 EACCES:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权能 EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志 ENOENT:key指定的消息队列不存在同时msgflg中不指定IPC_CREAT标志 ENOMEM:需要建立消息队列,但内存不足 ENOSPC:需要建立消息队列,但已达到系统的最大消息队列容量
对队列执行多种操作。他和另外两个与信号量及共享存储有关的函数(semctl和shmctl)都是类似于ioctl的函数(亦即垃圾桶函数)。
#include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:成功:0,失败-1
msqid:消息队列对象的标识符
cmd:消息队列进行操作
IPC_STAT:取此队列的msqid_ds结构,并将它存放在buf中
IPC_SET:将字段msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_bytes从buf指向的结构复制到,与这个队列相关的msqid_ds结构中。
此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid,另一种是具有超级用户特权的进程。
只有超级用户才能增加msg_qbytes的值。
IPC_EMID:从系统中删除该消息队列以及仍在该队列中的所有数据。这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将得到错误。
此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cui或msg_perm.uid;另一种是具有超级用户特权的进程。
buf:缓存msqid_ds结构
struct msqid_ds { struct ipc_perm msg_perm; /* Ownership and permissions */ time_t msg_stime; /* Time of last msgsnd(2) */ time_t msg_rtime; /* Time of last msgrcv(2) */ time_t msg_ctime; /* Time of last change */ unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */ msgqnum_t msg_qnum; /* Current number of messages in queue */ msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */ pid_t msg_lspid; /* PID of last msgsnd(2) */ pid_t msg_lrpid; /* PID of last msgrcv(2) */ };
其中又有ipc_perm结构:
struct ipc_perm { key_t __key; /* Key supplied to msgget(2) */ uid_t uid; /* Effective UID of owner */ gid_t gid; /* Effective GID of owner */ uid_t cuid; /* Effective UID of creator */ gid_t cgid; /* Effective GID of creator */ unsigned short mode; /* Permissions */ unsigned short __seq; /* Sequence number */ };
调用msgsnd将数据放到消息队列中
#include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功0,失败-1
msqid:消息队列识别码
msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收消息,是用户定义的通用结构。
msgsz:消息的大小
msgflg: 0当消息队列满时,msgsnd会阻塞,直到消息能写进队列
IPC_NOWAIT当消息队列已满时,msgsnd函数不等待立即返回
IPC_NOERROR若发送的消息大于size字节,则把消息截断,截断部分将丢弃,且不通知发送进程
msgp结构为:
struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ };
msgrcv从队列中取用消息
#include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); 返回值:成功返回消息数据部分的长度,出错-1 msqid:消息队列识别码
msgp:消息结构体,和msgsnd一样 msgsz:接收消息的大小 msgtyp: 0接收第一个消息
>0接收类型等于msgtyp的第一个消息
<0接收类型等于或小于msgtyp绝对值的第一个消息 msgflg: 0阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
IPC_NOWAIT如果没有返回条件的消息调用立即返回
IPC_EXCEPT与msgtype配合使用返回队列中第一个类型不为msgtype的消息
IPC_NOERROR如果队列中满足条件的消息内容大于所请求的size字节,则把消息截断并丢弃截断部分
消息队列使用的例子:
1 #include <stdio.h> 2 #include <sys/msg.h> 3 #include <sys/types.h> 4 #include <sys/ipc.h> 5 #include <string.h> 6 7 #define TEXT_SIZE 512 8 9 struct msgbuf { 10 long mtype; 11 char mtext[TEXT_SIZE]; 12 }; 13 14 int main(int argc, char *argv[]) 15 { 16 int msqid; 17 pid_t pid; 18 struct msgbuf msg; 19 20 msqid = msgget(IPC_PRIVATE, IPC_CREAT|0666); 21 if(msqid == -1) 22 { 23 printf("create msg queue failed!\n"); 24 return -1; 25 } 26 27 pid = fork(); 28 if(pid < 0) { 29 printf("fork failed!\n"); 30 return -1; 31 } else if(pid == 0) { /* child */ 32 msgrcv(msqid, &msg, sizeof(msg), 1, IPC_NOWAIT); 33 printf("child: msg.mtext is %s\n", msg.mtext); 34 strcpy(msg.mtext, "Hello, too!"); 35 msgsnd(msqid, &msg, sizeof(msg), IPC_NOWAIT); 36 } else { /* parent */ 37 msg.mtype = 1; 38 strcpy(msg.mtext, "Hello!"); 39 msgsnd(msqid, &msg, sizeof(msg), IPC_NOWAIT); 40 sleep(2); 41 msgrcv(msqid, &msg, sizeof(msg), 1, IPC_NOWAIT); 42 printf("parent:msg.mtext is %s\n", msg.mtext); 43 } 44 return 0; 45 }
无欲速,无见小利。欲速,则不达;见小利,则大事不成。