【进程】进程通信-消息队列
发展
unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便。消息队列(报文队列)则克服了这些缺点。
定义
消息队列就是一个消息的链表。可以把消息看做一个记录,具有特定的格式。进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。
分类
目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息对列,系统V消息对列目前被大量使用。
持续性
系统V消息对列是随内核持续的,只有在内核重启或者人工删除时,该消息对列才会被删除。
键值
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息列的键值。
#include<sys/types.h> #include<sys/ipc.h> key_t ftok(char *pathname,char proj)
- 功能:返回文件名对应的键值。
- pathname:文件名
- proj:项目名(不为0即可)
打开/创建
#include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int msgget(key_t key,int msgflg)
- key:键值,由ftok获得。
- msgflg:标志位,消息队列的访问权限。
- 返回值:与键值key相对应的消息队列描述字。
- IPC_CREAT:创建一个新的消息对列
- IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息对列已经存在,则返回错误
- IPC_NONWAIT:读写消息队列要求无法得到满足时,不阻塞。
以下两种情况下,将创建一个新的消息对列:
- 如果没有与键值key相对应的消息队列,并且msgflg中包括了IPC_CREAT标志位。
- key参数为IPC_PRIVATE。
发送消息
#include<sys/types.h> #include<sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid,struct msgbuf *msgp,int msgsz,int msgflg)
- 功能:向消息队列中发送一条消息。
- msqid:已打开的消息队列ID
- msgp:存放消息的结构
- msgsz:消息数据长度
- msg:发送标志,有意义的msgflg标志为IPC_NONWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。
消息格式
struct msgbuf { long mtype; /*消息类型>0*/ char mtext[1]; /*消息数据的首地址*/ }
接收消息
#include<sys/types.h> #include<sys/ipc.h> #include <sys/msg.h> int msgrecv(int msqid,void*msgp,int msgsz,long msgtyp,int msgflg)
功能:从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指向的msgbuf结构中。在成功读取一条消息以后,队列中的这条消息将被删除。
msgp:接收消息的缓冲区
msgtyp:
- 0:接收消息队列中第一个消息
- 大于0:接收消息队列中第一个类型为msgtyp的消息
- 小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息
msgflg:0,若无消息函数会一直阻塞
读消息程序
1 /********************************************************** 2 *程序要求: 创建一个消息队列,使两个进程能够通过它实现数据通讯。 3 *功能描述: 本程序创建或打开一个消息队列,并从消息队列中读出消息直至遇 4 * 到字符串“end”。 5 **********************************************************/ 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <errno.h> 10 #include <unistd.h> 11 #include <sys/types.h> 12 #include <sys/ipc.h> 13 14 struct my_msg_st 15 { 16 long int my_msg_type; 17 char some_text[BUFSIZ]; 18 }; 19 20 /* 21 * 程序入口 22 * */ 23 int main(void) 24 { 25 int running=1; 26 int msgid; 27 struct my_msg_st some_data; 28 long int msg_to_receive=0; 29 30 /*创建消息队列*/ 31 msgid=msgget((key_t)1234,0666 | IPC_CREAT); 32 if(msgid==-1) 33 { 34 fprintf(stderr,"msgget failed with error: %d\n",errno); 35 exit(EXIT_FAILURE); 36 } 37 38 /*循环从消息队列中接收消息*/ 39 while(running) 40 { 41 /*读取消息*/ 42 if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1) 43 { 44 fprintf(stderr,"msgrcv failed with error: %d\n",errno); 45 exit(EXIT_FAILURE); 46 } 47 48 printf("You wrote: %s",some_data.some_text); 49 50 /*接收到的消息为“end”时结束循环*/ 51 if(strncmp(some_data.some_text,"end",3)==0) 52 { 53 running=0; 54 } 55 } 56 57 /*从系统内核中移走消息队列*/ 58 if(msgctl(msgid,IPC_RMID,0)==-1) 59 { 60 fprintf(stderr,"msgctl(IPC_RMID) failed\n"); 61 exit(EXIT_FAILURE); 62 } 63 exit(EXIT_SUCCESS); 64 }
写消息程序
1 /********************************************************** 2 *程序要求: 创建一个消息队列,使两个进程能够通过它实现数据通讯。 3 *功能描述: 本程序创建或打开一个消息队列,并向消息队列中写入消息直至遇 4 * 到字符串“end”。 5 **********************************************************/ 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <errno.h> 10 #include <unistd.h> 11 #include <sys/types.h> 12 #include <sys/ipc.h> 13 14 #define MAX_TEXT 512 15 16 struct my_msg_st 17 { 18 long int my_msg_type; 19 char some_text[MAX_TEXT]; 20 }; 21 22 /* 23 * 程序入口 24 * */ 25 int main(void) 26 { 27 int running=1; 28 struct my_msg_st some_data; 29 int msgid; 30 char buffer[BUFSIZ]; 31 32 /*创建消息队列*/ 33 msgid=msgget((key_t)1234,0666 | IPC_CREAT); 34 if(msgid==-1) 35 { 36 fprintf(stderr,"msgget failed with error:%d\n",errno); 37 exit(EXIT_FAILURE); 38 } 39 40 /*循环向消息队列中添加消息*/ 41 while(running) 42 { 43 printf("Enter some text:"); 44 fgets(buffer,BUFSIZ,stdin); 45 some_data.my_msg_type=1; 46 strcpy(some_data.some_text,buffer); 47 48 /*添加消息*/ 49 if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0)==-1) 50 { 51 fprintf(stderr,"msgsed failed\n"); 52 exit(EXIT_FAILURE); 53 } 54 55 /*用户输入的为“end”时结束循环*/ 56 if(strncmp(buffer,"end",3)==0) 57 { 58 running=0; 59 } 60 } 61 exit(EXIT_SUCCESS); 62 }