进程间通信--消息队列
来源:互联网 发布:知乎一小时 编辑:程序博客网 时间:2024/06/05 02:06
1.创建消息队列
#include <sys/msg.h>
int msgget(key_t key,int flags);
参数中key用来转换成一个标识符,flags表明函数的行为。
//creat_msg.c
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int qid;
key_t key;
key=113;
qid=msgget(key,IPC_CREAT|0666);//创建一个权限为0666的消息队列
if(qid<0){
perror("msgget");
exit(1);
}
printf("created queue id : %d/n",qid);
system("ipcs -q");//查看系统IPC的状态
return 0;
}
结果:
./creat_msg
created queue id : 0
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00000071 0 alei 666 0 0
函数msgctl可以在队列上做多种操作。
#include <sys/msg.h>
int msgctl(int msqid,int cmd,struct msqid_ds * buf);
返回值: 0 ,如果成功。
- 1,如果失败:errno = EACCES (没有读的权限同时cmd 是IPC_STAT )
EFAULT (buf 指向的地址无效)
EIDRM (在读取中队列被删除)
EINVAL (msgqid无效, 或者msgsz 小于0 )
EPERM (IPC_SET或者IPC_RMID 命令被使用,但调用程序没有写的权限)
下面我们看一下可以使用的几个命令(即cmd参数):
IPC_STAT
读取消息队列的数据结构msqid_ds,并将其存储在b u f指定的地址中。
IPC_SET
设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。
IPC_RMID
从系统内核中移走消息队列
//del_msg.c
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc ,char * argv[])
{
int qid;
if(argc!=2){
puts("usage:del_msg queue_id");
exit(1);
}
qid=atoi(argv[1]);
system("ipcs -q");
if((msgctl(qid,IPC_RMID,NULL))<0){//删除指定的消息队列
perror("msgctl");
exit(1);
}
system("ipcs -q");
printf("successfully removed %d queue/n",qid);
return 0;
}
结果:
alei@alei-desktop:~/linux/code/14$ ./del_msg
usage:del_msg queue_id
alei@alei-desktop:~/linux/code/14$ ./del_msg 0
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00000071 0 alei 666 0 0
------ Message Queues --------
key msqid owner perms used-bytes messages
successfully removed 0 queue
2.读写消息队列
将一个消息加入队列:
#include <sys/msg.h>
intmsgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);
返回值:如果成功,0。
如果失败,-1:errno=EAGAIN(队列已满,并且使用了IPC_NOWAIT)
EACCES(没有写的权限)
EFAULT(msgp地址无效)
EIDRM(消息队列已经删除)
EINTR(当等待写操作时,收到一个信号)
EINVAL(无效的消息队列标识符,非正数的消息类型,或
者无效的消息长度)
ENOMEM(没有足够的内存复制消息缓冲区)
系统调用msgsnd()的第一个参数是消息队列标识符,它是由系统调用msgget返回的。第二个参数是msgp,是指向消息缓冲区的指针。参数msgsz中包含的是消息的字节大小,但不包括消息类型的长度(4个字节)。
参数msgflg可以设置为0(此时为忽略此参数),或者使用IPC_NOWAIT。
如果消息队列已满,那么此消息则不会写入到消息队列中,控制将返回到调用进程中。如果没有指明,调用进程将会挂起,直到消息可以写入到队列中。
ptr指向一个msgbuf的结构,定义如下:
struct msgbuf{
long mtype;
char mbuf[];
}
长度根据具体的消息来定,但是切记:消息不能以NULL结尾。
使用msgrcv可以从队列中读取消息:
#include <sys/msg.h>
int msgrcv(int msqid,struct msgbuf * msgp,int msgsz,long mtype,int msgflg);
返回值:如果成功,则返回复制到消息缓冲区的字节数。
如果失败,则返回-1:errno=E2BIG(消息的长度大于msgsz,没有MSG_NOERROR)
EACCES(没有读的权限)
EFAULT(msgp指向的地址是无效的)
EIDRM(队列已经被删除)
EINTR(被信号中断)
EINVAL(msgqid无效,或者msgsz小于0)
ENOMSG(使用IPC_NOWAIT,同时队列中的消息无法满足要求) 很明显,第一个参数用来指定将要读取消息的队列。第二个参数代表要存储消息的消息缓冲区的地址。第三个参数是消息缓冲区的长度,不包括mtype的长度,它可以按照如下的方法计算:
msgsz=sizeof(structmymsgbuf)-sizeof(long);
第四个参数是要从消息队列中读取的消息的类型。如果此参数的值为0,那么队列中最长时间的一条消息将返回,而不论其类型是什么。
如果调用中使用了IPC_NOWAIT作为标志,那么当没有数据可以使用时,调用将把ENOMSG返回到调用进程中。否则,调用进程将会挂起,直到队列中的一条消息满足msgrcv()的参数要求。如果当客户端等待一条消息的时候队列为空,将会返回EIDRM。如果进程在等待消息的过程中捕捉到一个信号,则返回EINTR。
//snd_msg.c
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct msg{
long msg_types;
char msg_buf[511];
};
int main( void ) {
int qid;
int pid;
int len;
struct msg pmsg;
pmsg.msg_types = getpid(); //消息类型为当前进程的id
sprintf (pmsg.msg_buf,"hello!this is :%d/n/0", getpid() );//初始化消息
len = strlen ( pmsg.msg_buf ); //或者可理解为sizeof(struct msg)-sizeof(long)
if ( (qid=msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0 ) { //创建一个消息队列
perror ( "msgget" );
exit (1) ;
}
if ( (msgsnd(qid, &pmsg, len, 0 )) < 0 ){ //想消息队列中发送消息
perror ( "msgsn" );
exit ( 1 );
}
printf ("successfully send a message to the queue: %d /n", qid);
exit ( 0 ) ;
}
//rcv_msg.c
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFSZ 4096
struct msg{
long msg_types;
char msg_buf[511];
};
int main( int argc, char * argv[] ) {
int qid;
int len;
struct msg pmsg;
if ( argc != 2 ){
perror ( "USAGE: read_msg <queue ID>" );
exit ( 1 );
}
qid = atoi ( argv[1] );
len = msgrcv ( qid, &pmsg, BUFSZ, 0, 0 );
if ( len > 0 ){
pmsg.msg_buf[len] = '/0'; //为消息添加结束符
printf ("reading queue id :%05ld/n", qid ); //输出队列id
printf ("message type : %05ld/n", pmsg.msg_types );
printf ("message length : %d bytes/n", len );
printf ("mesage text: %s/n", pmsg.msg_buf);
}
else if ( len == 0 )
printf ("have no message from queue %d/n", qid );
else {
perror ( "msgrcv");
exit (1);
}
system("ipcs -q");
return 0;
}
结果:
alei@alei-desktop:~/linux/code/14$ ./snd_msg
successfully send a message to the queue: 98304
alei@alei-desktop:~/linux/code/14$ ./rcv_msg 98304
reading queue id :98304
message type : 05788
message length : 20 bytes
mesage text: hello!this is :5788
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00000000 98304 alei 666 0 0
- 进程间通信--消息队列
- 进程间通信--消息队列
- 进程间通信--消息队列
- 进程间通信--消息队列
- LINUX进程通信--消息队列
- Linux进程通信-消息队列
- Vxworks 进程间通信1--消息队列
- 进程间消息队列通信
- 进程间通信:消息队列
- 进程间通信--消息队列
- 进程间通信-消息队列
- 进程间通信-消息队列
- 进程间通信----消息队列
- 进程间通信-消息队列
- 进程间通信-消息队列
- 消息队列 进程间通信
- 进程间通信---消息队列
- 进程间通信--消息队列
- 桌面托盘程序
- 关于常见排序算法的稳定性分析和结论
- SQL Server2000日期时间的处理
- PKU1737 解题报告 Connected Graph __高精度加法,乘法,减法,组合数
- C#.Net中的反射机制使用入门
- 进程间通信--消息队列
- JavaScript For EmEditor
- How to build Multi-Language Web Sites with ASP.NET 2.0 and VS.Net 2005
- SQL server 日志太大的处理方法
- JMX与commons-modeler (by quqi99)
- jsp与tomcat相关知识整理
- 案例研究:使用python获取中央电视台的节目单
- 完美解决Ubuntu9.04 无法启用桌面效果的问题
- 图论 BFS 血缘关系问题