SystemV IPC –消息队列
参与Helper2416开发板助学计划心得
这篇帖子主要是关于消息队列的学习心得。
这也是SystemV IPC机制中的最后一个咯.
消息队列的定义:
“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。
“消息队列”是在消息的传输过程中保存消息的容器。
消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。
消息队列提供了一种从一个进程向另一个进程发送一个数据块(相当与一个消息,但不一定是一个完整的消息,可能存在几个数据块组成一个消息的情况)的方法,而且,每个数据块都被认定为含有一个类型,接收进程可以独立地接收含有不同类型值的数据块。但是与管道一样,每个数据块都有一个最大长度限制(当一个完整的消息长度大于一个数据块的最大限制长度的时候,就需要使用两个或者多个数据块分开传递这个消息了),系统中所有队列包含的全部数据块的总长度也有一个上限。
消息队列提供了一种在两个不相关的进程之间传递数据的详单简单的方法,与命名管道类似,但是消息队列独立于发送和接收进程而存在,这消除了在同步命名管道的打开和关闭时可能产生的一些困难。
共享内存函数定义如下:
#include
int msgctl(int msqid, int cmd, structmsqid_ds *buf);
int msgget(key_t key, int msgflg);
int msgrcv(int msqid, void *msg_ptr,size_t msg_sz, long int msgtype, int msgflg);
int msgsend(int msqid, const void*msg_ptr, size_t msg_sz, int msgflg);
与信号量和共享内存一样,通常情况下sys/msg.h文件会自动包含sys/types.h与sys/ipc.h文件
Msgget
函数原型: int msgget(key_t key, int msgflg);
函数功能: 创建和访问一个消息队列
函数返回: 如果调用成功,将返回一个正整数,即消息队列标识符。如果调用失败,就返回-1。
参数说明: 第一个参数key,与其他IPC机制一样,程序必须提供一个键值来命名某个特定的消息队列。
第二个参数msgflag,由9个权限标志位组成,由IPC_CREAT定义的一个特殊位必须和权限标志位按位或才能创建一个新的消息队列,在设置IPC_CREAT标志时,如果给出的是一个已有的消息队列的键也不会产生错误,如果消息队列已有,则IPC_CREAT标志将会被忽略。
Msgsnd
函数原型int msgsend(int msqid, const void *msg_ptr, size_t msg_sz,int msgflg);
函数功能: 把消息(数据块)添加到消息队列中。
函数返回: 如果调用成功,返回0,同时消息数据的一份副本将被放到消息队列中。如果调用失败,就返回-1。
参数说明: 消息的结构受到两方面的约束,首先,它的长度必须小于系统规定的上线(其实分开发也可以);其次,它必须以一个长整型成员变量开始,接收函数将用这个成员变量来确定消息的类型。当使用消息时,最好把消息结构定义成以下形式:
struct my_message{
longint message_type;
/*the data you wish to transfer */
}
由于在消息的接收中要用到message_type,所以不能忽略此成员哦!
第一个参数msqid,是由msgget函数返回的消息队列标识符。
第二个参数msg_ptr,是一个指向准备发送消息的指针,记得必须要以一个长整型变量开始哦。
第三个参数msg_sz,是msg_ptr指向的消息的长度,这个长度不包括长整型消息类型成员的长度。
第四个参数msgflg,控制在当前消息队列满或者队列消息到达系统范围的限制时将要发生的事情。如果msgflg中设置了IPC_NOWAIT标志,函数将立即返回,不发送消息,并且返回值为-1,如果msgflg的IPC_NOWAIT标志被清除,则发送进程将挂起以等待队列中腾出可用空间。
Magrsv
函数原型: int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, longint msgtype, int msgflg);
函数功能: 从一个消息队列中获取消息。
函数返回: 调用成功返回放到接收缓冲区中的字节数,消息被复制到有msg_ptr指向的用户分配的缓冲区中,然后删除消息队列中的对应消息。失败时返回-1。
参数说明:第一个参数msqid,是由msgget函数返回的消息队列标识符。
第二个参数msg_ptr,是一个指向准备发接收息的指针,记得必须要以一个长整型变量开始哦。
第三个参数msg_sz,是msg_ptr指向的消息的长度,这个长度不包括长整型消息类型成员的长度。
第四个参数msgtype,是一个长整型,它可以实现一种简单形式的接收优先级,如果msgtype的值为0,就获取队列中的第一个可用消息。如果它的值大于0,将获取具有相同消息类型值的第一个消息。如果它的值小于0,将获取消息类型等于或小于msgtype的绝对值的第一个消息。
第五个参数msgflg,控制在当消息队列没有相应类型的消息可以接收时将要发生的事情。如果msgflg中设置了IPC_NOWAIT标志,函数将立即返回,并且返回值为-1,如果msgflg的IPC_NOWAIT标志被清除,则进程将挂起以等待一条相应类型的消息到达。
Msgctl
函数原型: int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数功能: 对消息队列的一些控制操作,(包括删除操作)
函数返回: 调用成功返回0,否则会返回-1。如果删除消息队列时,某个进程正在msgsnd或者msgrsv函数中等待,这两个函数将失败。
参数说明:msqid_ds结构至少包含以下成员:
struct msqid_ds{
uid_tmsg_perm.uid;
uid_tmsg _perm.gid;
mode_tmsg _perm.mod;
}
第一个参数msq_id是msgget返回的共享内存标识符。
第二个参数cmd是要采取的动作,它可以取如下三个值
IPC_STAT:把msqid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为msqid_ds结构中给出的值
IPC_RMID:删除共享内存
第三个参数buf是一个指针,它指向包含共享内存模式和访问权限的结构。
实践代码
Msg0.c 接收端
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <sys/msg.h>
- struct my_msg_st{
- long int my_msg_type;
- char some_text[BUFSIZ];
- };
- int main()
- {
- int running = 1;
- int msgid;
- struct my_msg_st some_data;
- long int msg_to_receive = 0;
-
- // 首先获取消息队列
- msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
-
- if(msgid == -1){
- fprintf(stderr, "msgget failed with error : %d\n",errno);
- exit(EXIT_FAILURE);
- }
-
- //从消息队列中获取消息,知道遇见end消息为止。
- while(running){
- if(msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1){
- fprintf(stderr, "msgrsv failed with error : %d\n",errno);
- exit(EXIT_FAILURE);
- }
- printf("You wrote: %s",some_data.some_text);
- if(strncmp(some_data.some_text, "end", 3) == 0){
- running = 0;
- }
- }
-
- //删除消息队列
- if(msgctl(msgid, IPC_RMID, 0) == -1){
- fprintf(stderr, "msgctl(IPC_RMID) failed\n");
- exit(EXIT_FAILURE);
- }
-
- exit(EXIT_SUCCESS);
- }
复制代码
Msg1.c 发送端
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <sys/msg.h>
- #define MAX_TEXT 512
- struct my_msg_st{
- long int my_msg_type;
- char some_text[MAX_TEXT];
- };
- int main()
- {
- int running = 1;
- int msgid;
- struct my_msg_st some_data;
- char buffer[BUFSIZ];
-
- // 首先创建消息队列
- msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
-
- if(msgid == -1){
- fprintf(stderr, "msgget failed with error : %d\n",errno);
- exit(EXIT_FAILURE);
- }
-
- //从键盘输入消息,并把消息放入消息队列。
- while(running){
- printf("Enter some text:");
- fgets(buffer, BUFSIZ, stdin);
- some_data.my_msg_type = 1;
- strcpy(some_data.some_text, buffer);
-
- if(msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1){
- fprintf(stderr, "msgsnd failed\n");
- exit(EXIT_FAILURE);
- }
- if(strncmp(buffer, "end", 3) == 0){
- running = 0;
- }
- }
-
- exit(EXIT_SUCCESS);
- }
复制代码
运行结果
- [jyxtec@localhost msg]$ gcc msg0.c -o msg0
- [jyxtec@localhost msg]$ gcc msg1.c -o msg1
- [jyxtec@localhost msg]$ ./msg1
- Enter some text:hello
- Enter some text:I'm yuanlai
- Enter some text:end
- [jyxtec@localhost msg]$ ./msg0
- You wrote: hello
- You wrote: I'm yuanlai
- You wrote: end
- [jyxtec@localhost msg]$
复制代码
论坛ID:yuanlai2010
发表时间:2014-09-02