您的位置:首页 > 其它

进程间通信--消息队列

2009-08-11 16:06 169 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: