消息队列例程
Msgget建立消息队列,msgget(key,IPC_CREAT|0660);key键值以及属性和权限
msgsnd(msgid,(void*)&msg_parent,sizeof(msg_parent)-sizeof(long),IPC_NOWAIT)
消息ID,消息地址,消息长度,以及阻塞设置等
函数原型:int msgsnd ( int msgid , struct msgbuf*msgp , int msgsz, int msgflg );
参数说明:
传给msgsnd()函数的第一个参数msqid 是消息队列对象的标识符(由msgget()函数得
到),第二个参数msgp 指向要发送的消息所在的内存,第三个参数msgsz 是要发送信息 的长度(字节数),可以用以下的公式计算:
msgsz = sizeof(struct mymsgbuf) - sizeof(long);
第四个参数是控制函数行为的标志,可以取以下的值:
0,忽略标志位;
IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线
程。如果不指定这个参数,线程将被阻塞直到消息被可以被写入。
msgrcv(msgid,(void*)&msg_child,sizeof(msg_child)-sizeof(long),msg_type_child,IPC_NOWAIT)
消息ID , 消息地址,消息长度,消息种类,阻塞设置等
函数定义:int msgrcv( int msgid , struct msgbuf* msgp , int msgsz , long msgtyp, int msgflg);
参数:
函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。第四个参数mtype
指定了函数从队列中所取的消息的类型。函数将从队列中搜索类型与之匹配的消息并将 之返回。不过这里有一个例外。如果mtype 的值是零的话,函数将不做类型检查而自动返 回队列中的最旧的消息。第五个参数依然是是控制函数行为的标志,取值可以是:
0,表示忽略;
IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数
的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件 的消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果 进程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,
剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不 被取出。
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
typedefstruct
{
long int msg_type;
unsigned char text[255];
}st_msg;
#defineIPCKEY 0x111
intmain(void)
{
int msgid = 0;
unsigned char r_buf[20];
unsigned char w_buf[20];
key_t key = 0;
pid_t pid = 0;
st_msg msgdata={0,{0}};
//memset(msgdata,0,sizeof(msgdata));
key = ftok("/dev/null",IPCKEY);
msgid = msgget(key,IPC_CREAT|0660);
if(msgid == -1)
{
if(errno != EEXIST)
perror("msgget invalid\n");
}
pid = fork();
if(pid == 0)
{
long int msg_type_child = 2;
st_msg msg_child={0,{0}};
//memset(msg_child,0,sizeof(msg_child));
sleep(2);
printf("This is a Child prosess\n");
if(msgrcv(msgid,(void*)&msg_child,sizeof(msg_child)-sizeof(long),msg_type_child,IPC_NOWAIT)<0)
{
perror("msgrcv invalid\n");
exit(2);
}
printf("the second num is %d\n",msg_child.text[0]);
msg_type_child=1;
if(msgrcv(msgid,(void*)&msg_child,sizeof(msg_child)-sizeof(long),msg_type_child,IPC_NOWAIT)<0)
{
perror("msgrcv invalid\n");
exit(2);
}
printf("the first num is %d\n",msg_child.text[0]);
exit(1);
}
else if(pid >0)
{
long int msg_type_parent = 0;
st_msg msg_parent={0,{0}};
//memset(msg_parent,0,sizeof(msg_parent));
msg_parent.msg_type = 1;
msg_parent.text[0]=2;
msg_parent.text[1]=3;
printf("This is a Parent process to send the first num,the numis %d\n",msg_parent.text[0]);
if(msgsnd(msgid,(void*)&msg_parent,sizeof(msg_parent)-sizeof(long),IPC_NOWAIT)<0)
{
perror("msgsnd invalid\n");
exit(1);
}
msg_parent.msg_type = 2;
msg_parent.text[0]=3;
msg_parent.text[1]=4;
printf("This is a Parent process to send second num,the num is%d\n",msg_parent.text[0]);
if(msgsnd(msgid,(void*)&msg_parent,sizeof(msg_parent)-sizeof(long),IPC_NOWAIT)<0)
{
perror("msgsnd invalid\n");
exit(1);
}
//sleep(2);
wait();
}
else
printf("Fork invalid\n");
if(msgctl(msgid,IPC_RMID,0)==-1)
{
perror("msgctl IPC_RMIDinvalid\n");
}
return 0;
}
运行结果
分析:
父进程发送两个消息,消息type有两种,一个是type=1,一个是type=2,子进程接受消息,根据设置的
信号msg_type_child接受,在msg_type_child=1时,挑选出消息队列中type=1的信息。由于父进程首先结束,为避免僵尸进程的形成,在父进程中wait等待子进程结束