消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,消息队列具有内核持续性;
每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值;
消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)
cat /proc/sys/kernel/msgmax 最大消息长度限制,8192=8K
cat /proc/sys/kernel/msgmnb 消息队列总的字节数,16384 = 16K
cat /proc/sys/kernel/msgmni 消息条目数,169
内核为每个IPC对象维护一个数据结构,在调用msgctl的时候就会用到;
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) */ }; //The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET): 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 */ };
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);对消息队列进行控制
2:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);用来创建和访问一个消息队列
3:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);参数msgp指向类似于下面的结构体,形式一样,但是具体的值自己改,msgbuf这个名字一定要改:
4:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);msgid: 由msgget函数返回的消息队列标识码
5:
#include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id);用这个函数为消息队列产生一个key值;
进程先创建一个消息队列,并向该消息队列中写入消息,消息类型是自身的PID;然后睡眠3秒之后再从消息队列中按照消息类型读取消息;
从运行结果可以看出,当写入之后,消息队列的大小变为了12, 当将消息读走之后消息队列的大小变为了0;
/************************************************************************* > File Name: msg1.cpp > Author: > Mail: > Created Time: 2015年12月17日 星期四 20时25分44秒 ************************************************************************/ #include <iostream> #include <cstdlib> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> #include <unistd.h> #include <string.h> using namespace std; struct msg_buf { long mtype; /* message type, must be > 0 */ char mtext[100]; /* message data */ }; /* 生成一个key值,ftok(首先要先创建一个文件myMsgFile) 创建消息队列,msgget 生成消息结构体对象并填充消息类型-一般是PID和数据内容 将消息写到消息队列 睡眠3秒 从消息队列里面读出来 */ int main() { key_t key; key = ftok("./myMsgFile", 'k'); int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666); if(msgid == -1){ if(errno == EEXIST){ key = ftok("./myMsgFile", 'k'); msgid = msgget(key, IPC_CREAT | 0666); } else{ cout << "msgget error..." << endl; exit(-1); } } struct msg_buf msgbuf; int msg_type = getpid(); msgbuf.mtype = msg_type; strcpy(msgbuf.mtext, "message data"); int ret = msgsnd(msgid, &msgbuf, strlen(msgbuf.mtext), IPC_NOWAIT); if(ret == -1){ cout << "msgsnd error..." << endl; exit(-1); } sleep(3); memset(&msgbuf, 0, sizeof(msgbuf)); ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf), msg_type, IPC_NOWAIT); if(ret == -1){ cout << "msgrcv error..." << endl; exit(-1); } cout << "receive the data is: " << msgbuf.mtext << endl; exit(0); }
这次是父子进程通过消息队列来传递信息;
进程先创建一个消息队列,并向该消息队列中写入消息,消息类型是自身的PID;然后又向该消息队列中写入消息,消息类型是111;此时查看消息队列已用了26字节;
然后睡眠5秒之后创建子进程,子进程再从消息队列中获得消息类型位111的消息并读走;读走了13字节,还有一个消息,剩下13字节;
/************************************************************************* > File Name: msg1.cpp > Author: > Mail: > Created Time: 2015年12月17日 星期四 20时25分44秒 ************************************************************************/ #include <iostream> #include <cstdlib> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> using namespace std; struct msg_buf { long mtype; /* message type, must be > 0 */ char mtext[100]; /* message data */ }; /* 生成一个key值,ftok(首先要先创建一个文件myMsgFile) 创建消息队列,msgget 生成消息结构体对象并填充消息类型-一般是PID和数据内容 将消息写到消息队列 睡眠3秒 从消息队列里面读出来 */ int main() { key_t key; key = ftok("./myMsgFile", 'k'); int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666); if(msgid == -1){ if(errno == EEXIST){ key = ftok("./myMsgFile", 'k'); msgid = msgget(key, IPC_CREAT | 0666); } else{ cout << "msgget error..." << endl; exit(-1); } } struct msg_buf msgbuf; int msg_type = getpid(); msgbuf.mtype = msg_type; strcpy(msgbuf.mtext, "message1 data"); int ret = msgsnd(msgid, &msgbuf, strlen(msgbuf.mtext), IPC_NOWAIT); if(ret == -1){ cout << "msgsnd error..." << endl; exit(-1); } memset(&msgbuf, 0, sizeof(msgbuf)); msgbuf.mtype = 111; strcpy(msgbuf.mtext, "message2 data"); ret = msgsnd(msgid, &msgbuf, strlen(msgbuf.mtext), IPC_NOWAIT); if(ret == -1){ cout << "msgsnd error..." << endl; exit(-1); } sleep(5); pid_t pid = fork(); if(pid < 0){ cout << "fork error..." << endl; exit(-1); } else if (pid == 0){ memset(&msgbuf, 0, sizeof(msgbuf)); ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf), 111, IPC_NOWAIT); //获得第二条消息 if(ret == -1){ cout << "msgrcv error..." << endl; exit(-1); } cout << "child process receive the data is: " << msgbuf.mtext << endl; cout << "child exit..." << endl; exit(0); } int child_status; wait(&child_status); cout << "parent exit..." << endl; exit(0); }