(1)消息队列的基本概念:
消息队列可以简单理解为双向链表。消息队列提供了一种从进程向另一个进程发送一个数据的方法,在读或写数据时,要根据数据的大小全部读写。管道是基于字节流的,而消息队列是基于消息。每个数据块都被认为是有一个类型,接收者进程接受的书记可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。
(2)消息队列的创建:
key:可以认为是一个端口号,也可以是由函数ftok生成。
msgget:可以有两个值,也可以有一个。当只有一个值时是IPC_CREAT:表示如果这个IPC不存在就需要创建一个,如果存在则只需打开操作。当有两个值时是:IPC_CREAT和IPC_EXCL:表示如果存在IPC时就会报错,如果这个IPC则创建一个IPC。
(3)消息队列的读与写:
msgid:消息队列的标识码
msgp:指向消息缓冲区的指针,用来暂时存储发送和接受的消息,是一个用户可以定义的通用结构。形态为:
msgsz:消息的大小
msgtyp:从消息队列内读取的消息形态,如果值为0表示消息队列中的所有消息都会被读取
msgflg:用来指明核心程序在队列没有数据的情况下采取的行动。如果msgflg和常数IPC_NOWAIT合用,则在msgsnd()执行时如消息队列已满,则msgsnd()将不会阻塞,并且会立即返回-1,如果执行的是msgrcv(),则在消息队列呈空时返回-1,并设定错误码为ENOMSG。当msgflg为0时,msgsnd()以及msgrev()在队列呈满或呈空的情形时,采取阻塞等待的处理方式。
(4)消息队列的属性:
msgctl系统调用对msgqid表示的消息队列执行cmd操作,系统调用了三种cmd操作:IPC_STAT该命令用来获取消息队列对应的msqid_ds数据,并对其保存到buf指定的地址空间。IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf中。IPC_RMID:从内核中删除msqid标识的消息队列。
(5)用消息队列实现进程之间的通信:
comm.h
#ifndef _COMM_H_
2 #define _COMM_H_
3 #include<stdio.h>
4 #include<sys/types.h>
5 #include<sys/ipc.h>
6 #include<sys/sem.h>
7 #include<string.h>
8 #include<stdlib.h>
9 #define PATHNAME "."
10 #define PROJ_ID 0x6666
11 #define SERVICE_TYPE 1
12 #define CLIENT_TYPE 2
13
14 struct msgbuf
15 {
16 long mtype;
17 char mtext[1024];
18 };
19
20 int CreateMsgQueue();
21 int GetMsgQueue();
22 int SendMegQueue(int msgmid,int type,const char *msg);
23 int RecvMsgQueue(int msgmid,int type,const char *out);
24 int DestoryMsgQueue(int msgid);
25 #endif
comm.c
#include"comm.h"
2
3 static int CommMsgQueue(int flags)
4 {
5 key_t _key=ftok(PATHNAME,PROJ_ID);
6 if (_key<0){
7 perror("ftok");
8 return -1;
9 }
10 int msgid=msgget(_key,flags);
11 if (msgid<0){
12 perror("msgget");
13 return -2;
14 }
15 return msgid;
16 }
17 int CreateMsgQueue()
18 {
19 return CommMsgQueue(IPC_CREAT|IPC_EXCL|0666);
20 }
21 int GetMsgQueue()
22 {
23 return CommMsgQueue(IPC_CREAT);
24 }
25 int DestoryMsgQueue(int msgid)
26 {
27 if(msgctl(msgid,IPC_RMID,NULL)<0){
28 perror("msgctl");
29 return -1;
30 }
31 return 0;
32 } 33 int SendMsgQueue(int msgid,int type,const char *msg) 34 { 35 struct msgbuf _mb; 36 _mb.mtype=type; 37 strcpy(_mb.mtext,msg); 38 if(msgsnd(msgid,&_mb,sizeof(_mb.mtext),0)<0){ 39 perror("msgsnd"); 40 return -1; 41 } 42 return 0; 43 } 44 int RecvMsgQueue(int msgid,int type,const char *out) 45 { 46 struct msgbuf _mb; 47 if(msgrcv(msgid,&_mb,sizeof(_mb.mtext),type,0)<0){ 48 perror("msgrcv"); 49 return -1; 50 } 51 strcpy(_mb.mtext,out); 52 return 0; 53 }
server.c
1 #include"comm.h" 2 3 int main() 4 { 5 int msgid=CreateMsgQueue(); 6 char buf[1024]; 7 while(1){ 8 buf[0]=0; 9 RecvMsgQueue(msgid,CLIENT_TYPE,buf); 10 printf("client say:%s\n",buf); 11 printf("please enter:"); 12 fflush(stdout); 13 ssize_t s=read(0,buf,sizeof(buf)-1); 14 if(s>0){ 15 buf[s-1]=0; 16 SendMsgQueue(msgid,SERVICE_TYPE,buf); 17 } 18 } 19 DestoryMsgQueue(msgid); 20 return 0; 21 }
client.c
#include"comm.h" 2 3 int main() 4 { 5 int msgid=CreateMsgQueue(); 6 char buf[1024]; 7 while(1){ 8 buf[0]=0; 9 printf("client enter:"); 10 fflush(stdout); 11 ssize_t s=read(0,buf,sizeof(buf)-1); 12 if(s>0){ 13 buf[s-1]=0; 14 SendMsgQueue(msgid,SERVICE_TYPE,buf); 15 } 16 RecvMsgQueue(msgid,CLIENT_TYPE,buf); 17 printf("server say:\n",buf); 18 } 19 return 0; 20 21 }