System V 消息队列(一)

本文深入解析了消息队列的工作原理及使用方法,包括消息队列的特性、内核中的表示方式、IPC对象数据结构以及创建、设置权限、状态查询等核心函数的应用。
一、消息队列
    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)


    
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值