消息队列常用操作函数如下:
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
int msgget(key_t key, int msgflg);
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
IPC对象数据结构:
内核为每个IPC对象维护一个数据结构
struct ipc_perm {
key_t __key; /* Key supplied to xxxget(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 */
};
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) */
};
msgget函数
功能:用来创建和访问一个消息队列
原型
int msgget(key_t key, int msgflg);
参数
key: 某个消息队列的名字
msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1
msgget函数参数关系图:
功能:消息队列的控制函数
原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数
msqid: 由msgget函数返回的消息队列标识码
cmd:是将要采取的动作,(有三个可取值)
返回值:成功返回0,失败返回-1
msgsnd函数
功能:把一条消息添加到消息队列中
原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数
msgid: 由msgget函数返回的消息队列标识码
msgp:是一个指针,指针指向准备发送的消息,
msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
返回值:成功返回0;失败返回-1
msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。
消息结构在两方面受到制约。首先,它必须小于系统规定的上限值;其次,它必须以一个long int长整数开始,接收者函数将利用这个长整数确定消息的类型
消息结构参考形式如下:
struct msgbuf
{
long mtype;
char mtext[100];
}
msgrcv函数
功能:是从一个消息队列接收消息
原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数
msgid: 由msgget函数返回的消息队列标识码
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=MSG_EXCEPT,接收类型不等于msgtype的第一条消息。
msg01.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int msg_id = msgget( 0x1234, 0666);
if(msg_id == -1)
{
printf("msgget error\n");
return -1;
}
return 0;
}
msg02.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int msg_id = msgget( 0x1234, 0666);
if(msg_id == -1)
{
printf("msgget error\n");
if(errno == ENOENT )
{
printf("No message queue exists for key\n");
return -1;
}
}
return 0;
}
msg03.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int msg_id = msgget( 0x1234, IPC_CREAT | 0666);
if(msg_id == -1)
{
printf("msgget error\n");
if(errno == ENOENT )
{
printf("No message queue exists for key\n");
return -1;
}
}
printf("get msg queue id = %d\n", msg_id);
struct msqid_ds mq;
if(msgctl(msg_id, IPC_STAT, &mq) != 0)
{
//printf("msgctl error\n");
perror("msgctl error:\n");
return -1;
}
int mode = mq.msg_perm.mode;
int curretSize = mq.__msg_cbytes;
int currentNumber = mq.msg_qnum;
printf("mode = %o, curretSize = %d, currentNumber = %d\n", mode, curretSize, currentNumber);
mq.msg_perm.mode = 0644;
if(msgctl(msg_id, IPC_SET, &mq) != 0)
{
perror("msgget err");
return -1;
}
return 0;
}
msg04.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int msg_id = msgget( 0x1234, IPC_CREAT | 0666);
if(msg_id == -1)
{
printf("msgget error\n");
if(errno == ENOENT )
{
printf("No message queue exists for key\n");
return -1;
}
}
printf("get msg queue id = %d\n", msg_id);
struct msqid_ds mq;
if(msgctl(msg_id, IPC_STAT, &mq) != 0)
{
//printf("msgctl error\n");
perror("msgctl error:");
return -1;
}
int mode = mq.msg_perm.mode;
int curretSize = mq.__msg_cbytes;
int currentNumber = mq.msg_qnum;
printf("mode = %o, curretSize = %d, currentNumber = %d\n", mode, curretSize, currentNumber);
if(msgctl(msg_id, IPC_RMID, NULL) != 0)
{
perror("msgctl error:");
return -1;
}
return 0;
}
消息队列的简单应用:
消息队列实现回射客户/服务器
echoclient.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
#define MSGMAX 8192
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[MSGMAX]; /* message data */
};
//思路:
//客户端发给服务器消息类型总是1
//服务器端回给客户端的type是对方进程号
//相当于服务器端 从消息队列中收消息,然后服务器端分类型回复客户端(通过消息队列)
//n个进程通过消息队列进行交换
//有没有产生死锁的可能
//n个客户端向服务器发送消息(本质上是向内核消息队列发送消息),若消息队列满了;服务区回射时,会阻塞。。造成程序死锁
//即使,非阻塞。。。仍然回阻塞。。
void echo_cli(int msgid)
{
int n;
int pid;
pid = getpid();
struct msgbuf msg;
memset(&msg, 0, sizeof(msg));
//消息内容由:自己的pid+键盘输入
*((int*)msg.mtext) = pid;
//消息类型 1
msg.mtype = 1;
while (fgets(msg.mtext+4, MSGMAX, stdin) != NULL)
{
if (msgsnd(msgid, &msg, 4+strlen(msg.mtext+4), 0) < 0)
ERR_EXIT("msgsnd");
//前四个字节是自己的pid
memset(msg.mtext+4, 0, MSGMAX - 4);
if ((n = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)
ERR_EXIT("msgsnd");
fputs(msg.mtext+4, stdout);
memset(msg.mtext+4, 0, MSGMAX-4);
}
}
int main(int argc, char *argv[])
{
int msgid;
msgid = msgget(0x1234, 0);
if (msgid == -1)
ERR_EXIT("msgget");
echo_cli(msgid);
return 0;
}
echoserver.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
#define MSGMAX 8192
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[MSGMAX]; /* message data */
};
void echo_srv(int msgid)
{
int n;
struct msgbuf msg;
memset(&msg, 0, sizeof(msg));
while (1)
{
if ((n = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)
ERR_EXIT("msgsnd");
int pid;
pid = *((int*)msg.mtext);
fputs(msg.mtext+4, stdout);
msg.mtype = pid;
msgsnd(msgid, &msg, n, 0);
}
}
int main(int argc, char *argv[])
{
int msgid;
msgid = msgget(0x1234, IPC_CREAT | 0666);
if (msgid == -1)
ERR_EXIT("msgget");
echo_srv(msgid);
return 0;
}