LINUX学习:System V消息队列
介绍:
1.消息队列提供了一个从一个进程向另外一个进程发送数据块的方法
2.每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
3.消息队列也有管道一样的不足,就是每个消息最大的长度是有上限的(MSGMAX),每个消息队列
的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也是有一个上限的。
每个IPC对象都在内核维护着一个数据结构,
消息不同于刘模式,消息是有边界的,消息都是被打包在一个一个的数据包里的。
那么我们看下消息队列结构:
消息队列有4个重要的队列函数:
##创建一个消息队列
int msgget(ket_t key, int msgflg)
key:某个消息队列的名字
msgflg:由九个权限标志构成, 它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回非负整数, 即该消息队列的标识码, 失败返回-1;
##i消息队列的控制函数
int msgctl(int msgqid, int cmd, struct msqid_ds *buf);
msqid:由msgget函数返回的消息队列标识码
cmd:即将要采取的动作(有三个取值)
返回值:成功返回0,失败返回-1;
IPC_STAT:
将消息队列的信息保存到下面结构体:
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_RMID:
删除该消息队列
3.msgsnd
将一条消息添加到消息队列中
int msgsnd(int msqid, const void *msgo, size_t msgsz, int msgflg);
msgid:消息队列标识码
msgp:一个指向准备发送的消息的指针;
msgsz:msgp指向的消息的长度,这个长度不含保存消息类型的那个long int长整形;
msgflg:控制着当前队列消息满或者到达系统上线时要法神的事情
返回值:成功返回0,失败返回-1;
##msgflg = IPC_NOWAIT表示队列不等待,返回EAGAIN错误。
消息结构在两方面受到制约,首先它必须小于系统规定的上限值;其次,它必须以一个long int长整数
开始, 接收者函数将利用这个长整数确定消息的类型;
消息结构参考如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
下面我们写一个发送函数练习一下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define ERR_EXIT(m) \ do { \ perror(m);\ exit(EXIT_FAILURE);\ }while(0) struct msgbuf{ long mtype; char mtext[1]; }; int main(int argc, const char *argv[]) { if(argc != 3) { fprintf(stderr, "usgage :%s <bytes> <type>\n", argv[0]); exit(EXIT_FAILURE); } int len = atoi(argv[1]); int type = atoi(argv[2]); int msgid; //创建一个消息队列 msgid = msgget(1111, 0); if(msgid == -1) ERR_EXIT("msgget"); struct msgbuf *ptr; ptr = (struct msgbuf*)malloc(sizeof(long) + len); ptr->mtype = type; if(msgsnd(msgid, ptr, len, IPC_NOWAIT) <0) ERR_EXIT("msgsnd"); return 0; }
4.msgrcv函数
从一个消息队列接收消息,略微比snd函数复杂;
原型 ssize_t msgrcv(int msgqid, void *msgp, size_t msgsz, long msgtype, int msgflg);
msgid:消息队列标识码
msgp:一个指向准备发送的消息的指针;
msgsz:msgp指向的消息的长度,这个长度不含保存消息类型的那个long int长整形;
msgtype:他可以实现接收优先级的简单形式
msgflg:控制着当前队列消息中没有相应类型的消息可供接收时将要发送的事;
返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1;
msgtype=0 返回队列第一条消息
msgtype>0 返回队列第一条等于msgtype的消息;
msgtype<0返回队列第一类型小于等于msgtype绝对值的消息
msgflg=IPC_NOWAIT ,队里没有可读消息不等待,返回ENOMSG错误
msgflg=MSG_NOERROR,消息大小超过msgsz时被阶段
msgtype》0且msgflg=MSC)EXCEPT,接收第一条
这里插空介绍一个函数
getopt 可以实现对函数的 选项设置
int main(int argc, const char *argv[]) { int flag = 0; int type = 0; int opt; while(1) { opt = getopt(argc, argv,"nt:"); if(opt == '?') exit(EXIT_FAILURE); if(opt == -1) exit(0); switch(opt) { case 'n': // printf("NNNN\n"); flag |= IPC_NOWAIT; break; case 't': /* printf("TTTTT\n"); int n = atoi(optarg); printf("(b=%d)\n", n); */ type = atoi(optarg); break; }