`
memorymyann
  • 浏览: 271047 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

进程通行之报文消息队列

阅读更多

报文和消息队列又是进程间通行的一种手段(用于发送大量信息,它没有信号那种异步性和命名管道很像,能发送接收大量数据,但管道的缺点是数据没有组织性)。

 

它的特点,他的生命周期很长,一个消息队列创建后,让他消亡的方式有2种:

1.从启系统,整个内存的刷新。

2.自己手动销毁他。

说他克服了数据组织问题,我们知道一个管道,你在1点写了一些数据,读进程没有去读。你2点时候又写了一批数据,那么这2批数据就会合在一起,你无法区分它们中间的断点在哪儿。消息队列不同之处在于它克服了这一点,至于他是如何区分2块数据的,这就根据客户指定的type,看到具体代码。

 

[root@liumengli MSG]# cat send_msg.c (这里是发送消息的代码)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define BUFF_LEN 1024
#define RET_ERROR 1
#define RET_OK 0

typedef struct msg_send_struct { //这就是一个消息的数据结构
        long my_type; //我们就是根据这个字段来区分每块消息的
        char my_text[BUFF_LEN];
} msg_send_struct;

int main() {
        char * path = "/";
        int i_porject_id = 7;
        key_t key;
        msg_send_struct msg_send; //定义发送消息

        int i_ret;
        int i_msg_id;
        int i_flag = 0666|IPC_CREAT; //为消息管道的创建指定参数,IPC_CREAT表示这个消息队列是创建,而不是搜索已经存在的消息队列

        key = ftok(path, i_porject_id);//为消息队列生成一个key,当然你也可以手动指定,当你运气很好没有和已经窜在的消息队列的key起冲突的时候
        if(key == 1) {
                printf("building key error\n");
                exit(1);
        }

        i_msg_id = msgget(key, i_flag);//根据你的参数决定是创建还是搜索KEY值得消息队列

        if(i_msg_id == -1) {
                printf("create msg queue error\n");
                exit(1);
        }
        printf("i_msg_id = %d\n", i_msg_id);

        msg_send.my_type = 1;
        strcpy(msg_send.my_text, "hello world"); //初始化消息
        i_ret = msgsnd(i_msg_id, &msg_send, strlen("hello world") + 1, IPC_NOWAIT);//开始发送,nowait表示如果队列中消息满了当前进程不等待直接返回错误,反之很容易理解吧

        if(i_ret == -1) {
                printf("msg send error\n");
                exit(1);
        }

        exit(0);
}
[root@liumengli MSG]# cat rec_msg.c (接收消息的代码)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define BUFF_LEN 1024
#define RET_ERROR 1
#define RET_OK 0

typedef struct msg_rec_struct {//和前面一样
        long my_type;
        char my_text[BUFF_LEN];
} msg_rec_struct;
int main() {
        char * path = "/";
        int i_project_id = 7;
        key_t key;
        int i_ret;
        int i_msg_id;
        int i_flag = IPC_EXCL;//这个就和上面的CRATE差距了,EXCL是搜索,找不到是会出错的
        msg_rec_struct msg_rec;

        key = ftok(path, i_project_id);//生成KEY值,放心打印后你会发现2个KEY值是相同的
        if(key == -1) {
                printf("building key error\n");
                exit(1);
        }

        i_msg_id = msgget(key, i_flag);//首先找到队列

        if(i_msg_id == -1) {
                printf("create msg queue error\n");
                exit(1);
        }
        printf("i_msg_id = %d\n", i_msg_id);

        i_ret = msgrcv(i_msg_id, &msg_rec, BUFF_LEN, 1, 0);//获取消息队列中的消息,注意我们第4个参数是1,他的意思是我们要去my_type是1的消息,因为我们在发送中,把发送消息的mytype设置的是1

        if(i_ret == -1) {
                printf("recive message error\n");
                exit(1);
        }
        printf("recive message: %s\n", msg_rec.my_text);

        msgctl(i_msg_id, IPC_RMID, NULL);//这个是销毁消息队列
}
[root@liumengli MSG]# ./send_msg
i_msg_id = 98304
[root@liumengli MSG]# ./rec_msg
i_msg_id = 98304
recive message: hello world
[root@liumengli MSG]#
下面就是我们的运行了,我们看到,我们成功的把hello world的字符串从send_msg发送到了rec_msg,当然你可以在shell里面用指令去销毁这个队列,命令是ipcrm -q (消息队列的ID)我么销毁,看看会发生什么。

[root@liumengli MSG]# ./send_msg
i_msg_id = 131072
[root@liumengli MSG]# ipcrm -q 131072
[root@liumengli MSG]# ./rec_msg
create msg queue error
可以看出在搜索是否有131072这个队列时候就出错误了。最后补充下权限,队列不是随随便便就能访问的,内核在实现的时候加了权限限制。

1.超级用户可以访问任何队列,只要你能得到队列的KEY值即可。

2.普通用户只能访问同组人或者自己的队列.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics