System V IPC ---- 消息队列详解

System V IPC ---- 消息队列


一、System V 消息队列创建及操作流程:

ftok函数
msgget函数
msgsnd函数
msgrcv函数
msgctl函数
msgctl函数
begin
获取键值
创建新消息队列
发送消息
接收消息
消息队列控制操作

二、System V 消息队列相关API:

Ⅰ、msgget()

msgget()

Ⅱ、msgsnd() & msgrcv()

msgsnd()&msgrcv()
msgsnd()&msgrcv()
说明:

  • msgp是一个由程序员自己定义的结构体指针,该结构体常规形式:
struct mymsg
{
	long mtype;		//消息类型
	char mtext[];	//消息内容
}

1、其中,mtext[]长度和内容任意,无需是一个字符数组。因此,mgsp参数的类型为void *,这样就允许传入任意结构的指针。
2、使用msgsnd()发送消息时,必须要将消息结构中的mtype的值设为一个大于0的值
3、使用msgrcv()接收消息时,msgtyp参数控制选择接收的消息:

  • msgtyp==0时,删除队列中的第一条消息并将其返回给调用进程(符合队列的FIFO);
  • msgtyp>0时,将队列中 第一条 mtype等于msgtyp的消息删除并将其返回给调用进程。 通过指定不同的msgtyp值,多个进程能够从同一个消息队列中读取消息而不出现竞争读取同一条消息的情况。(一般都是用每个进程自己的进程ID进行匹配);
  • msgtyp<0时,删除并返回队列中mtype小于msgtyp绝对值的消息,如果这种消息有多个,则取第一个mtype最小的消息。

  • 每个消息队列都有一个关联的msqid_ds结构体,其形式如下:
struct msqid_ds
{
	strcut ipc_perm 	msg_perm;		//消息权限信息结构体
	time_t 				msg_stime;		//最后一次发送消息的时间
	time_t				msg_rtime;		//最后一次接收消息的时间
	time_t				msg_ctime;		//最后一次状态变更的时间
	unsigned long		_msg_cbytes;	//当前消息队列中的数据尺寸
	msgqnum_t			msg_qnum;		//当前消息队列中的消息个数
	msglen_t			msg_qbytes;		//消息队列的最大数据尺寸
	pid_t				msg_lspid;		//最后一个发送消息的进程PID
	pid_t				msg_lrpid;		//最后一个接收消息的进程PID
};

其中,权限相关的消息用如下结构体来表示:

struct ipc_perm
{
	key_t			_key;	//当前消息队列的key值
	uid_t			uid;	//当前消息队列所有者的有效UID
	gid_t			gid;	//当前消息队列所有者的有效GID
	uid_t			cuid;	//当前消息队列创建者的有效UID
	gid_t			cgid;	//当前消息队列创建者的有效GID
	unsigned short 	mode;	//消息队列的读写权限
	unsigned short 	_seq;	//序列号
};

  • 当使用 IPC_INFO(相关信息存放在/proc/sys/kernel中)时,需要定义一个如下结构体来获取系统关于消息队列的限制信息,并且将这个结构体的指针强制类型转化为第三个参数的类型:
struct msginfo
{
	int					msgpool;	//系统消息总尺寸(千字节为单位)的最大值
	int 				msgmap;		//系统消息个数最大值
	int					msgmax;		//系统单个消息尺寸最大值
	int					msgmnb;		//写入消息队列字节数最大值
	int 				msgmni;		//系统消息队列个数最大值
	int 				msgssz;		//消息段尺寸
	int 				msgtql;		//系统中所有消息队列中的消息总数最大值
	unsigned short int 	msgseg;		//分配给消息队列的数据段最大值
};

当使用选项MSG_INFO时,跟IPC_INFO一样也是获得一个msginfo结构体,但是有如下几点不同:

  • msgpool记录的是系统当前存在的MSG的个数总和
  • msgmap记录的是系统当前所有MSG中的消息个数总和
  • msgtql记录的是系统当前所有MSG中的所有消息的所有字节数总和


三、System V 消息队列的缺点:

Ⅰ、 System V 消息队列是通过标识符引用的,而不是文件描述符。这意味着各种基于文件描述符的I/O技术将无法应用于消息队列上。
Ⅱ、 使用键key而不是文件名来标识消息队列会增加额外的程序设计复杂性,同时还需要使用ipcsipcrm来替换lsrmftok()函数通常能产生一个唯一的键,但却无法百分百保证。使用IPC_PRIVATE能确保产生唯一的队列标识符,但需要使这个标识符对需要用到它的其他进程可见。
Ⅲ、 消息队列是无法连接的,内核不会像对待管道、FIFO以及socket那样维护引用队列的进程数。因此,就需要注意以下问题:

  • 一个应用程序何时能够安全地删除一个消息队列?(不管是否有进程在后面某个时刻需要从队列中读取数据而过早地删除队列会导致数据丢失。<相对于其他采用文件描述符的I/O在接到删除指令会等待最后一个使用该文件的进程使用完毕后才会删除该文件来说的>)
  • 应用程序如何确保不再使用的队列会被删除?

Ⅳ、 消息队列的总数、消息的大小以及单个队列的容量都是有限制的。(可以在/proc/sys/kernel中对相应文件进行修改配置,但是操作麻烦,不方便移植)

综上,最好避免使用System V 消息队列,而用 POSIX 消息队列代替。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值