进程间通信系列 之 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例
进程间通信系列 之 概述与对比 http://blog.csdn.net/younger_china/article/details/15808685
进程间通信系列 之 共享内存及其实例 http://blog.csdn.net/younger_china/article/details/15961557
进程间通信系列 之 共享内存简单实例 http://blog.csdn.net/younger_china/article/details/15991081
进程间通信系列 之 信号(理论) http://blog.csdn.net/younger_china/article/details/15976961
进程间通信系列 之 信号实例 http://blog.csdn.net/younger_china/article/details/15968715
进程间通信系列 之 信号综合实例 http://blog.csdn.net/younger_china/article/details/15980485
进程间通信系列 之 命名管道FIFO及其应用实例 http://blog.csdn.net/younger_china/article/details/15808531
进程间通信系列 之 管道(客户端和服务端通信) http://blog.csdn.net/younger_china/article/details/15809281
进程间通信系列 之 信号量详解及编程实例 http://blog.csdn.net/younger_china/article/details/15808531
进程间通信系列 之 消息队列函数及其范例 http://blog.csdn.net/younger_china/article/details/15503871
进程间通信系列 之 消息队列应用实例 http://blog.csdn.net/younger_china/article/details/15808501
进程间通信系列 之 socket套接字及其实例 http://blog.csdn.net/younger_china/article/details/15809163
进程间通信系列 之 socket套接字实例 http://blog.csdn.net/younger_china/article/details/15809207
消息队列函数由msgget、msgctl、msgsnd、msgrcv四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。
1. msgget函数原型
msgget(得到消息队列标识符或创建一个消息队列对象) |
||
所需头文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函数说明 |
得到消息队列标识符或创建一个消息队列对象并返回消息队列标识符 |
|
函数原型 |
int msgget(key_t key, int msgflg) |
|
函数传入值 |
key |
0(IPC_PRIVATE):会建立新的消息队列 |
大于0的32位整数:视参数msgflg来确定操作。通常要求此值来源于ftok返回的IPC键值 |
||
msgflg |
0:取消息队列标识符,若不存在则函数会报错 |
|
IPC_CREAT:当msgflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符 |
||
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列则报错 |
||
函数返回值 |
成功:返回消息队列的标识符 |
|
出错:-1,错误原因存于error中 |
||
附加说明 |
上述msgflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定消息队列的存取权限 |
|
错误代码 |
EACCES:指定的消息队列已存在,但调用进程没有权限访问它 EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志 ENOENT:key指定的消息队列不存在同时msgflg中没有指定IPC_CREAT标志 ENOMEM:需要建立消息队列,但内存不足 ENOSPC:需要建立消息队列,但已达到系统的限制 |
如果用msgget创建了一个新的消息队列对象时,则msqid_ds结构成员变量的值设置如下:
Ÿ msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime设置为0。
Ÿ msg_ctime设置为当前时间。
Ÿ msg_qbytes设成系统的限制值。
Ÿ msgflg的读写权限写入msg_perm.mode中。
Ÿ msg_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
2. msgctl函数原型
msgctl (获取和设置消息队列的属性) |
||
所需头文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函数说明 |
获取和设置消息队列的属性 |
|
函数原型 |
int msgctl(int msqid, int cmd, struct msqid_ds *buf) |
|
函数传入值 |
msqid |
消息队列标识符 |
cmd |
IPC_STAT:获得msgid的消息队列头数据到buf中 |
|
IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes |
||
buf:消息队列管理结构体,请参见消息队列内核结构说明部分 |
||
函数返回值 |
成功:0 |
|
出错:-1,错误原因存于error中 |
||
错误代码 |
EACCESS:参数cmd为IPC_STAT,确无权限读取该消息队列 EFAULT:参数buf指向无效的内存地址 EIDRM:标识符为msqid的消息队列已被删除 EINVAL:无效的参数cmd或msqid EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行 |
3. msgsnd函数原型
msgsnd (将消息写入到消息队列) |
||
所需头文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函数说明 |
将msgp消息写入到标识符为msqid的消息队列 |
|
函数原型 |
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) |
|
函数传入值 |
msqid |
消息队列标识符 |
msgp |
发送给队列的消息。msgp可以是任何类型的结构体,但第一个字段必须为long类型,即表明此发送消息的类型,msgrcv根据此接收消息。msgp定义的参照格式如下: struct s_msg{ /*msgp定义的参照格式*/ |
|
msgsz |
要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度 |
|
msgflg |
0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列 |
|
IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回 |
||
IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。 |
||
函数返回值 |
成功:0 |
|
出错:-1,错误原因存于error中 |
||
错误代码 |
EAGAIN:参数msgflg设为IPC_NOWAIT,而消息队列已满 EIDRM:标识符为msqid的消息队列已被删除 EACCESS:无权限写入消息队列 EFAULT:参数msgp指向无效的内存地址 EINTR:队列已满而处于等待情况下被信号中断 EINVAL:无效的参数msqid、msgsz或参数消息类型type小于0 |
msgsnd()为阻塞函数,当消息队列容量满或消息个数满会阻塞。消息队列已被删除,则返回EIDRM错误;被信号中断返回E_INTR错误。
如果设置IPC_NOWAIT消息队列满或个数满时会返回-1,并且置EAGAIN错误。
msgsnd()解除阻塞的条件有以下三个条件:
① 不满足消息队列满或个数满两个条件,即消息队列中有容纳该消息的空间。
② msqid代表的消息队列被删除。
③ 调用msgsnd函数的进程被信号中断。
4. msgrcv函数原型
msgrcv (从消息队列读取消息) |
||
所需头文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函数说明 |
从标识符为msqid的消息队列读取消息并存于msgp中,读取后把此消息从消息队列中删除 |
|
函数原型 |
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); |
|
函数传入值 |
msqid |
消息队列标识符 |
msgp |
存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同 |
|
msgsz |
要接收消息的大小,不含消息类型占用的4个字节 |
|
msgtyp |
0:接收第一个消息 |
|
>0:接收类型等于msgtyp的第一个消息 |
||
<0:接收类型等于或者小于msgtyp绝对值的第一个消息 |
||
msgflg |
0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待 |
|
IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG |
||
IPC_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息 |
||
IPC_NOERROR:如果队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃 |
||
函数返回值 |
成功:实际读取到的消息数据长度 |
|
出错:-1,错误原因存于error中 |
||
错误代码 |
E2BIG:消息数据长度大于msgsz而msgflag没有设置IPC_NOERROR EIDRM:标识符为msqid的消息队列已被删除 EACCESS:无权限读取该消息队列 EFAULT:参数msgp指向无效的内存地址 ENOMSG:参数msgflg设为IPC_NOWAIT,而消息队列中无消息可读 EINTR:等待读取队列内的消息情况下被信号中断 |
msgrcv()解除阻塞的条件有以下三个:
① 消息队列中有了满足条件的消息。
② msqid代表的消息队列被删除。
③ 调用msgrcv()的进程被信号中断。
消息队列使用程序范例
5. 消息队列控制范例
msgctl.c源代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <error.h>
#define TEXT_SIZE 512 struct msgbuf
{
long mtype ;
char mtext[TEXT_SIZE] ;
} ; int main(int argc, char **argv)
{
int msqid ;
struct msqid_ds info ;
struct msgbuf buf ;
struct msgbuf buf1 ;
int flag ;
int sendlength, recvlength ; msqid = msgget( IPC_PRIVATE, 0666 ) ;
if ( msqid < 0 )
{
perror("get ipc_id error") ;
return -1 ;
} buf.mtype = 1 ;
strcpy(buf.mtext, "happy new year!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
buf.mtype = 3 ;
strcpy(buf.mtext, "good bye!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
} flag = msgctl( msqid, IPC_STAT, &info ) ;
if ( flag < 0 )
{
perror("get message status error") ;
return -1 ;
}
printf("uid:%d, gid = %d, cuid = %d, cgid= %d\n" ,
info.msg_perm.uid, info.msg_perm.gid, info.msg_perm.cuid, info.msg_perm.cgid ) ;
printf("read-write:%03o, cbytes = %lu, qnum = %lu, qbytes= %lu\n" ,
info.msg_perm.mode&0777, info.msg_cbytes, info.msg_qnum, info.msg_qbytes ) ;
system("ipcs -q") ;
recvlength = sizeof(struct msgbuf) - sizeof(long) ;
memset(&buf1, 0x00, sizeof(struct msgbuf)) ; flag = msgrcv( msqid, &buf1, recvlength ,3,0 ) ;
if ( flag < 0 )
{
perror("recv message error") ;
return -1 ;
}
printf("type=%d, message=%s\n", buf1.mtype, buf1.mtext) ; flag = msgctl( msqid, IPC_RMID,NULL) ;
if ( flag < 0 )
{
perror("rm message queue error") ;
return -1 ;
}
system("ipcs -q") ; return 0 ;
}
编译 gcc msgctl.c –o msgctl。
执行 ./msg,执行结果如下:
uid:1008, gid = 1003, cuid = 1008, cgid= 1003
read-write:666, cbytes = 1024, qnum = 2, qbytes= 163840
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00000000 65536 zjkf 666 1024 2
type=3, message=good bye!
------ Message Queues --------
key msqid owner perms used-bytes messages
6. 两进程通过消息队列收发消息
(1)发送消息队列程序
msgsnd.c源代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>
#define TEXT_SIZE 512
struct msgbuf
{
long mtype ;
int status ;
char time[20] ;
char mtext[TEXT_SIZE] ;
} ;
char *getxtsj()
{
time_t tv ;
struct tm *tmp ;
static char buf[20] ;
tv = time( 0 ) ;
tmp = localtime(&tv) ;
sprintf(buf,"%02d:%02d:%02d",tmp->tm_hour , tmp->tm_min,tmp->tm_sec);
return buf ;
} int main(int argc, char **argv)
{
int msqid ;
struct msqid_ds info ;
struct msgbuf buf ;
struct msgbuf buf1 ;
int flag ;
int sendlength, recvlength ;
int key ; key = ftok("msg.tmp", 0x01 ) ;
if ( key < 0 )
{
perror("ftok key error") ;
return -1 ;
} msqid = msgget( key, 0600|IPC_CREAT ) ;
if ( msqid < 0 )
{
perror("create message queue error") ;
return -1 ;
} buf.mtype = 1 ;
buf.status = 9 ;
strcpy(buf.time, getxtsj()) ;
strcpy(buf.mtext, "happy new year!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
buf.mtype = 3 ;
buf.status = 9 ;
strcpy(buf.time, getxtsj()) ;
strcpy(buf.mtext, "good bye!") ;
sendlength = sizeof(struct msgbuf) - sizeof(long) ;
flag = msgsnd( msqid, &buf, sendlength , 0 ) ;
if ( flag < 0 )
{
perror("send message error") ;
return -1 ;
}
system("ipcs -q") ;
return 0 ;
}
(2)接收消息队列程序
msgrcv.c源代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define TEXT_SIZE 512
struct msgbuf
{
long mtype ;
int status ;
char time[20] ;
char mtext[TEXT_SIZE] ;
} ; int main(int argc, char **argv)
{
int msqid ;
struct msqid_ds info ;
struct msgbuf buf1 ;
int flag ;
int recvlength ;
int key ;
int mtype ; key = ftok("msg.tmp", 0x01 ) ;
if ( key < 0 )
{
perror("ftok key error") ;
return -1 ;
} msqid = msgget( key, 0 ) ;
if ( msqid < 0 )
{
perror("get ipc_id error") ;
return -1 ;
} recvlength = sizeof(struct msgbuf) - sizeof(long) ;
memset(&buf1, 0x00, sizeof(struct msgbuf)) ;
mtype = 1 ;
flag = msgrcv( msqid, &buf1, recvlength ,mtype,0 ) ;
if ( flag < 0 )
{
perror("recv message error\n") ;
return -1 ;
}
printf("type=%d,time=%s, message=%s\n", buf1.mtype, buf1.time, buf1.mtext) ;
system("ipcs -q") ;
return 0 ;
}
(3)编译与执行程序
① 在当前目录下利用>msg.tmp建立空文件msg.tmp。
② 编译发送消息队列程序 gcc msgsnd.c -o msgsnd。
③ 执行./msgsnd,执行结果如下:
----- Message Queues --------
key msqid owner perms used-bytes messages
0x0101436d 294912 zjkf 600 1072 2
④ 编译接收消息程序 gcc msgrcv.c -o msgrcv
⑤ 执行./msgrcv,执行结果如下:
type=1,time=03:23:16, message=happy new year!
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0101436d 294912 zjkf 600 536 1
⑥ 利用ipcrm -q 294912删除该消息队列。因为消息队列是随内核持续存在的,在程序中若不利用msgctl函数或在命令行用ipcrm命令显式地删除,该消息队列就一直存在于系统中。另外信号量和共享内存也是随内核持续存在的。
摘录自《深入浅出Linux工具与编程》
进程间通信系列 之 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例的更多相关文章
- 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例
消息队列函数由msgget.msgctl.msgsnd.msgrcv四个函数组成.下面的表格列出了这四个函数的函数原型及其具体说明. 1. msgget函数原型 msgget(得到消息队列标识符或 ...
- Linux环境进程间通信(三):消息队列
linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...
- (转)Linux环境进程间通信----系统 V 消息队列列
转:http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix通 ...
- Linux下进程间通信方式——使用消息队列
一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的 ...
- 获取和设置消息队列的属性msgctl,删除消息队列
消息队列的属性保存在系统维护的数据结构msqid_ds中,用户可以通过函数msgctl获取或设置消息队列的属性. int msgctl(int msqid, int cmd, struct msqid ...
- Linux 进程间通信(posix消息队列 简单)实例
Linux 进程间通信(posix消息队列 简单)实例 详情见: http://www.linuxidc.com/Linux/2011-10/44828.htm 编译: gcc -o consumer ...
- 进程间通信IPC:消息队列,信号量,共享内存
2015.3.4星期三 阴天 进程间通信:IPC 文件对象:记录文件描述符,文件开关等 IPC标示符:系统全局的流水号两个进程要通信,打开的是唯一的对象进行通讯,通过key操作 XSI IPC:消息队 ...
- Linux进程间通信(System V) --- 消息队列
消息队列 IPC 原理 消息队列是消息的链式队列,如下图为消息队列的模型.整个消息队列有两种类型的数据结构. 1.msqid_ds 消息队列数据结构:描述整个消息队列的属性,主要包括整个消息队列的权限 ...
- 进程间通信 System V 消息队列
1.msgget (key_t ket,int flag) ; //创建一个新的消息队列或者访问一个已存在的消息队列 2.msgsnd(int msid, const void *ptr ,size_ ...
随机推荐
- c++ string 对象操作
字符串转换大小写如下: #include "stdafx.h" #include <iostream> #include <string> using na ...
- 计算机程序的思维逻辑 (74) - 并发容器 - ConcurrentHashMap
本节介绍一个常用的并发容器 - ConcurrentHashMap,它是HashMap的并发版本,与HashMap相比,它有如下特点: 并发安全 直接支持一些原子复合操作 支持高并发.读操作完全并行. ...
- JavaGUI版本销售管理系统
不知不觉中,本科阶段已经走过两个年头,诸多感慨,诸多向往,周遭的人和事物在不断的改变着,自己的目标也在不断改变,总之,世界一直在快速的发生着变化,快到我们无法捕捉,总的来说,过得很潇洒,就等考上研究生 ...
- resin远程调试配置,connection refused问题解决
http://john521.iteye.com/blog/1879805 这篇博客中讲的很好. 我在配置的过程中遇到了几个问题,记录一下: 1. 调试服务器监听的端口号,百度的开发机都限制了端口在某 ...
- web从入门开始(2)----基础
HTML文件结构 <html> <head>//网页头标记 <title>放置标题</title> </head> <body> ...
- ORACLE获取表信息方法
获取表: select table_name from user_tables; //当前用户的表 select table_name from all_tables; //所有用户的表 select ...
- windows phone 8.1开发:文件选择器FileOpenPicker
原文出自:http://www.bcmeng.com/fileopenpicker/ 今天小梦给大家分享一下 windows phone 8.1中的文件选择器,和之前的windows phone8的不 ...
- zookeeper + dubbo + spring boot
最近开始接触了分布式的一些东西,这里给自己作一个学习笔记. 这里只是做一个运行demo,具体的理论知识就不在这里阐述了. 1.zookeeper的安装与启动 下载地址:http://www.apach ...
- 设计模式的征途—1.单例(Singleton)模式
单例模式属于创建型模式的一种,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛.创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修 ...
- mvalidator手机端校验
官网地址:https://github.com/efri-yang/mobileValidate#%E5%8F%82%E6%95%B0 使用方法: html如下: <li class=" ...