linux 消息队列

来源:互联网 发布:飞思卡尔单片机官网 编辑:程序博客网 时间:2024/06/06 23:17
在 linux 系统下 消息队列的聊天室实现的过程: 1.消息队列 消息队列消息队列是消息的链接表,存放在内核中并由消息队列标识符标识.我们将称消息队列为 "队列" ,其标识符为"队列 I D" . m s g g e t 用于创建一个新队列或打开一个现存的队列. 用于创建一个新队列或打开一个现存的队列. m s g s n d 用于将新消息添加到队列尾端.每个消息包含一个正长整型类型字段,一个非负 用于将新消息添加到队列尾端.每个消息包含一个正长整型类型字段, 长度以及实际 数据字节(对应于长度) ,所有这些都在将消息添加到队列时,传送给 m s g s n d. m s g r c v 用于从队列中取消息 用于从队列中取消息. 我们并不一定要以先进先出次序取消息 也可以按消息的类型字段取消息. 取消息, 我们并不一定要以先进先出次序取消息,也可以按消息的类型字段取消息 每个队列都有一个 m s q i d d s 结构与其相关.此结构规定了队列的当前状态.如图(1-1) 图(1-1)msqid_ds 结构 调用的第一个函数通常是 m s g g e t,其功能是打开一个现存队列或创建一个新队列. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int flag) ; 返回:若成功则为消息队列 I D,若出错则为- 1 调用 m s g s n d 将数据放到消息队列上. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void * pt r, size_tnbytes, int flag) ; 返回:若成功则为 0,若出错则为- 1 正如前面提及的,每个消息都由三部分组成,它们是:正长整型类型字段,非负长度 (nbytes)以及实际数据字节(对应于长度) .消息总是放在队列尾端.ptr 指向一个长整型 数,它包含了正整型消息类型,在其后立即跟随了消息数据. (若 nbytes 是 0,则无消息数 据. )若发送的最长消息是 5 1 2 字节,则可定义下列结构: struct mymesg { QQ:230817742 2 作者:叶建敏 4/26/2010 long mtype; /* positive message type */ char mtext[512]; /* message dat,aof length n b y t e s * / }; 于是,p t r 就是一个指向 mymesg 结构的指针.接收者可以使用消息类型以非先进先出的次 序取消息.f l a g 的值可以指定为 IPC_NOWAIT.这类似于文件 I / O 的非阻塞 I / O 标志. 若消息队列已满 (或者是队列中的消息总数等于系统限制值, 或队列中的字节总数等于系统 限制值) 则指定 IPC_NOWAIT 使得 msgsnd 立即出错返回 EAGAIN. , 如果没有指定 IPC_NO WAIT,则进程阻塞直到(a)有空间可以容纳要发送的消息,或( b)从系统中删除了此队 列,或( c)捕捉到一个信号,并从信号处理程序返回.在第二种情况下,返回 E I D R M ( "标志符被删除".最后一种情况则返回 E I N T R.注意,对消息队列删除的处理不是很 ) 完善.因为对每个消息队列并没有设置一个引用计数器(对打开文件则有这种计数器) ,所 以删除一个队列使得仍在使用这一队列的进程在下次对队列进行操作时出错返回. 信号量机 构也以同样方式处理其删除.删除一个文件则要等到使用该文件的最后一个进程关闭了它, 才能删除文件的内容.msgrcv 从队列中取用消息. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgrcv(intm s q i d, void *ptr, size_t nbytes, long type, int flag) ; 返回:若成功则为消息数据部分的长度,若出错则为- 1 如同 msgsnd 中一样,p t r 参数指向一个长整型数(返回的消息类型存放在其中) ,跟随其后 的是存放实际消息数据的缓存.nbytes 说明数据缓存的长度.若返回的消息大于 nbytes,而 且在 f l a g 中设置了 MSGNOERROR,则该消息被截短(在这种情况下,不通知我们消息截 短了) .如果没有设置这一标志,而消息又太长,则出错返回 E2BIG(消息仍留在队列中) . 参数 type 使我们可以指定想要哪一种消息: type == 0 返回队列中的第一个消息. type > 0 返回队列中消息类型为 t y p e 的第一个消息. type < 0 返回队列中消息类型值小于或等于 t y p e 绝对值,而且在这种消息中,其类型值 又最小的消息.非 0t y p e 用于以非先进先出次序读消息.例如,若应用程序对消息赋优先 权,那么 t y p e 就可以是优先权值.如果一个消息队列由多个客户机和一个服务器使用,那 么 t y p e 字段可以用来包含客户机进程 I D.可以指定 flag 值为 IPC_NOWAIT,使操作不阻 塞.这使得如果没有所指定类型的消息,则 msgrcv 出错返回 ENOMSG.如果没有指定 IPC _NOWAIT,则进程阻塞直至(a)有了指定类型的消息,或(b)从系统中删除了此队列(出 错返回 E I D R M) ,或(c)捕捉到一个信号并从信号处理程序返回(出错返回 E I N T R) . 实例一消息队列与流管道的时间比较如若需要客户机和服务器之间的双向数据流, 可以使用 消息队列或流管道. 2.简单的消息队列聊天列子. 简单的消息队列聊天列子. 简单的消息队列聊天列子 /*服务端的代码*/ /*server.c*/ /*作者:叶建敏*/ /*QQ:230817742*/ QQ:230817742 3 作者:叶建敏 4/26/2010 #include <sys/ipc.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> //以上为程序所必须的头文件 struct msgbuf { long mtype; //消息类型 char mtext[100]; //消息正文 }; //定义一个结构体 msgbuf 用来存放消息的类型和消息的正文 int main() { FILE *fp; key_t key; pid_t pid; int msgid; //队列 ID 号 struct msgbuf msg1,msg2; //定义两个结构体变量 char wbuf[800]="",my_name[20]="",others_name[20]=""; // 消息内容,本地名字,对方名字 key=ftok(".",0xFF); //调用 ftok 函数,产生标准的 key if((msgid=msgget(key,IPC_CREAT|0666))<0) //调用 msgget 函数,创建和打开消息队列 { perror("msgger error"); exit(0); } printf("plese input you name:"); msg1.mtype=3; 型的姓名 memset(msg1.mtext,0,100);// 设置缓冲区的内容 fgets(wbuf,100,stdin);//将标准输入到 wbuf 缓冲区 wbuf[strlen(wbuf)-1]='\0'; strcpy(my_name,wbuf);//把 wbuf 里的内容复制到 my_name strcpy(msg1.mtext,wbuf);// msgsnd(msgid,&msg1,sizeof(msg1.mtext),0);//把消息添加到消息队列中 msgrcv(msgid,&msg2,100,4,0);//根据消息队列的消息类型接受对应的消息对 方的姓名 strcpy(others_name,msg2.mtext);//根据上面获得的数据把对方的的名字存 储到 others_name,存储是根据消息号存储 //消息类型为 3,此消息接受让对方对方接受的对应的消息类 //定义文件变量指针 QQ:230817742 4 作者:叶建敏 4/26/2010 fflush(stdout); if((pid=fork())<0)//创建一个子进程 { printf("erro"); exit(0); } if(pid==0) { while(1) { msg1.mtype=1; memset(msg1.mtext,0,100);//刷新 printf("%s:",my_name); fgets(wbuf,100,stdin); wbuf[strlen(wbuf)-1]='\0'; strcpy(msg1.mtext,wbuf); msgsnd(msgid,&msg1,sizeof(msg1.mtext),0); } }else { while(1) { msgrcv(msgid,&msg2,100,2,0); if((fp=fopen("data.txt","a+"))==NULL) { perror("打开失败记录"); return 0; } fprintf(fp,"%s:%s\n",others_name,msg2.mtext); fclose(fp); printf("\r%s:%s\n%s:",others_name,msg2.mtext,my_name); fflush(stdout); } } } QQ:230817742 5 作者:叶建敏 4/26/2010 /*哭护短的代码*/ /*client.c*/ /*作者:叶建敏*/ /*QQ:230817742*/ #include <sys/ipc.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> struct msgbuf { long mtype; //消息类型 char mtext[100]; //消息正文 }; int main() { FILE *fp; key_t key; pid_t pid; int msgid; //队列 ID struct msgbuf msg1,msg2; char wbuf[800]="",my_name[20]="",others_name[20]=""; key=ftok(".",0xFF); if((msgid=msgget(key,IPC_CREAT|0666))<0) { //创建队列 perror("msgger error"); exit(0); } printf("plese input you name:"); msg1.mtype=4; //消息类型为 3,此消息接受对方的姓名 memset(msg1.mtext,0,100);// 设置缓冲区的内容 fgets(wbuf,100,stdin);//将标准输入到 wbuf 缓冲区 wbuf[strlen(wbuf)-1]='\0'; strcpy(msg1.mtext,wbuf); strcpy(my_name,wbuf); msgsnd(msgid,&msg1,sizeof(msg1.mtext),0); msgrcv(msgid,&msg2,100,3,0); strcpy(others_name,msg2.mtext); QQ:230817742 6 作者:叶建敏 4/26/2010 fflush(stdout); if((pid=fork())<0) { printf("erro"); exit(0); } if(pid==0) { while(1) { msgrcv(msgid,&msg2,100,1,0); if((fp=fopen("data.txt","a+"))==NULL) { perror("打开失败记录"); return 0; } fprintf(fp,"%s:%s\n",others_name,msg2.mtext); fclose(fp); printf("\r%s:%s\n%s:",others_name,msg2.mtext,my_name); fflush(stdout); } }else { while(1) { msg1.mtype=2; memset(msg1.mtext,0,100);//刷新 printf("%s:",my_name); fgets(wbuf,100,stdin); wbuf[strlen(wbuf)-1]='\0'; strcpy(msg1.mtext,wbuf); msgsnd(msgid,&msg1,sizeof(msg1.mtext),0); } } } QQ:230817742 7 作者:叶建敏 4/26/2010 3.消息队列小例子 消息队列小例子 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/msg.h> #include <unistd.h> #include <sys/ipc.h> void msg_show_attr(int msg_id,struct msqid_ds msg_info) { int ret=-1; sleep(1); ret=msgctl(msg_id,IPC_STAT,&msg_info); if(ret==-1) { printf("get message wrong!\n"); exit(1); } printf("\n"); printf("now the crow word number is :%d\n",msg_info.msg_cbytes); printf("the message number is:%d\n",msg_info.msg_qnum); printf("the crow max number is:%d\n",msg_info.msg_qbytes); printf("the last message's pid is :%d\n",msg_info.msg_lspid); printf("the last receve meassage's pid is:%d",msg_info.msg_lrpid); printf("the last send time is:%s",ctime(&(msg_info.msg_stime))); printf("the printf("the last last receve changed time time is:%s",ctime(&(msg_info.msg_rtime))); is:%s",ctime(&(msg_info.msg_ctime))); printf("the message UID is :%d\n",msg_info.msg_perm.uid); printf("the message GID is :%d\n",msg_info.msg_perm.gid); } int main() { int ret=-1; int msg_flags,msg_id; key_t key; struct msgmbuf{ QQ:230817742 8 作者:叶建敏 4/26/2010 int mtype; char mtext[20]; }; struct msqid_ds msg_info; struct msgmbuf msg_mbuf; struct msgmbuf msg_mbuf1; struct msgmbuf msg_mbuf2; int msg_sflags,msg_rflags; char *msgpath="/home/yejianmin/"; key=ftok(msgpath,'f'); if(key!=-1) { printf("成功创建!\n"); } else { printf("KEY 失败"); } msg_flags=IPC_CREAT; msg_id=msgget(key,msg_flags|0x0777); if(msg_id==-1) { printf("found message error;\n"); return 0; } msg_show_attr(msg_id,msg_info); msg_sflags=IPC_NOWAIT; msg_mbuf.mtype=1; msg_mbuf1.mtype=2; msg_mbuf2.mtype=3; memcpy(msg_mbuf.mtext,"测试消息",sizeof("测试消息")); ret =msgsnd(msg_id,&msg_mbuf,sizeof("测试消息"),msg_sflags); memcpy(msg_mbuf1.mtext,"测试消息 1",sizeof("测试消息 1")); ret = msgsnd(msg_id,&msg_mbuf1,sizeof("测试消息"),msg_sflags); memcpy(msg_mbuf2.mtext,"测试消息 2",sizeof("测试消息 2")); ret = msgsnd(msg_id,&msg_mbuf2,sizeof("测试消息"),msg_sflags); printf("msg_mbuf.mtext=%s\n",msg_mbuf.mtext); printf("msg_mbuf1.mtext=%s\n",msg_mbuf1.mtext); printf("msg_mbuf2.mtext=%s\n",msg_mbuf2.mtext); if(ret==-1) { QQ:230817742 9 作者:叶建敏 4/26/2010 printf("发送失败!"); } msg_show_attr(msg_id,msg_info); msg_rflags=IPC_NOWAIT|MSG_NOERROR; ret =msgrcv(msg_id,&msg_mbuf,20,1,msg_rflags); printf("msg_mbuf.mtext=%s\n",msg_mbuf.mtext); ret=msgrcv(msg_id,&msg_mbuf1,20,2,msg_rflags); printf("msg_mbuf1.mtext=%s\n",msg_mbuf1.mtext); ret=msgrcv(msg_id,&msg_mbuf2,20,3,msg_rflags); printf("msg_mbuf2.mtext=%s\n",msg_mbuf2.mtext); if(-1==ret) { printf("rcv error\n"); } else { printf("rcv success ,length is :%d\n",ret); } msg_show_attr(msg_id,msg_info); msg_info.msg_perm.uid=8; msg_info.msg_perm.gid=8; msg_info.msg_qbytes=12345; ret=msgctl(msg_id,IPC_SET,&msg_info); msg_show_attr(msg_id,msg_info); msgctl(msg_id,IPC_RMID,&msg_info); return 0; }