一、消息队列
1、消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
2、每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
3、消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。
4、消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI),这三个参数都可以查看:
cjl@S405:~$ cat /proc/sys/kernel/msgmax #一条消息的长度
8192
cjl@S405:~$ cat /proc/sys/kernel/msgmnb # 一个消息队列总的容纳长度
16384
cjl@S405:~$ cat /proc/sys/kernel/msgmni #系统中创建消息队列的最大个数
1663
二. IPC对象数据结构
内核为每个IPC对象维护一个数据结构,在<sys/msg.h>头文件中,该头文件在ubuntu系统下的路径:/usr/include/linux

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) */
};
四.消息队列在内核中的表示
五.消息队列函数
返回值:
成功返回非负整数,即消息队列的标识码
失败:返回-1
#ipcrm -q msgid # 删除命令
#ipcrm -Q key # 删除命令,如何key为0,则不能删除
------------------------------------------------------------------------------------
删除消息队列:msg_rmid.c
设置消息队列的权限:msg_set.c
打印消息队列的状态信息:msg_stat.c
makefile文件:
1、消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
2、每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
3、消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。
4、消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI),这三个参数都可以查看:
cjl@S405:~$ cat /proc/sys/kernel/msgmax #一条消息的长度
8192
cjl@S405:~$ cat /proc/sys/kernel/msgmnb # 一个消息队列总的容纳长度
16384
cjl@S405:~$ cat /proc/sys/kernel/msgmni #系统中创建消息队列的最大个数
1663
二. IPC对象数据结构
内核为每个IPC对象维护一个数据结构,在<sys/msg.h>头文件中,该头文件在ubuntu系统下的路径:/usr/include/linux
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) */
};
四.消息队列在内核中的表示
消息队列是用链表实现的,这里需要提出的是MSGMAX指的是一条消息的纯数据大小的上限,下图是一个 消息队列,则其纯数据总和不能超过MSGMNB,像这样一条消息队列,系统含有的总数不能超过MSGMNI 个。
五.消息队列函数
(1) 功能:用来创建和访问一个消息队列
int msgget(key_t key, // 某个休息队列的名字
int msgflg); //由个权限标志组成,它们的用法和创建文件时使用的mode模式标志时一样的返回值:
成功返回非负整数,即消息队列的标识码
失败:返回-1
(2)功能:消息队列的控制函数
int msgctl(int msgid, //msgget函数返回的消息队列标识符
int cmd, // 采取的动作struct msgid_ds *buf); //
返回值: 成功返回0失败返回-1
cmd 的取值如下:
会用到的命令
-----------------------------------------------------------------------------------
# ipcs -q #查看IPC消息队列命令#ipcrm -q msgid # 删除命令
#ipcrm -Q key # 删除命令,如何key为0,则不能删除
------------------------------------------------------------------------------------
创建一个消息队列: msg_get.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)
int main()
{
int msgid;
//msgid = msgget(1234,0666 | IPC_CREAT);
msgid = msgget(1234,0666 | IPC_CREAT | IPC_EXCL);
//msgid = msgget(IPC_PRIVATE,0666 | IPC_CREAT | IPC_ECEC);// 创建的不能够共享的
//msgid = msgget(IPC_PRIVATE,0666);
msgid = msgget(1234,0); // 如果消息队列已经存在,则打开消息队列
if(msgid == -1)
ERR_EXIT("msgget err");
printf("msgget success \n");
printf("msgid=%d\n",msgid);
return 0;
}
删除消息队列:msg_rmid.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)
int main()
{
int msgid;
msgid = msgget(1234,0); // 如果消息队列已经存在,则打开消息队列
if(msgid == -1)
ERR_EXIT("msgget err");
printf("msgget success \n");
printf("msgid=%d\n",msgid);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
设置消息队列的权限:msg_set.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)
int main()
{
int msgid;
msgid = msgget(1234,0); // 如果消息队列已经存在,则打开消息队列
if(msgid == -1)
ERR_EXIT("msgget err");
printf("msgget success \n");
printf("msgid=%d\n",msgid);
struct msqid_ds buf;
msgctl(msgid,IPC_STAT,&buf); // 必须得先获取
sscanf("600","%o",(unsigned int *)&buf.msg_perm.mode); // 以八进制输入到buf
msgctl(msgid,IPC_SET,&buf); // 再设置
return 0;
}
打印消息队列的状态信息:msg_stat.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)
int main()
{
int msgid;
msgid = msgget(1234,0); // 如果消息队列已经存在,则打开消息队列
if(msgid == -1)
ERR_EXIT("msgget err");
printf("msgget success \n");
printf("msgid=%d\n",msgid);
struct msqid_ds buf;
msgctl(msgid,IPC_STAT,&buf);
printf("mode=%o\n",buf.msg_perm.mode);
printf("bytes=%ld\n",buf.__msg_cbytes);
printf("number=%d\n",(int)buf.msg_qnum);
printf("msgmnb=%d\n",(int)buf.msg_qbytes);
return 0;
}
makefile文件:
.PHONY:clean all
cc=gcc
CFLAGS=-Wall -g
BIN=msg_get msg_rmid msg_stat msg_set
all:$(BIN)
%.o:%.c
$(cc) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o $(BIN)