System V IPC(1)-消息队列

一.概述                                                   

System V三种IPC: 消息队列信号量共享内存 。这三种IPC最先出现在AT&T System v UNIX上面,并遵循XSI标准,有时候也被称为XSI IPC。

本文先探讨消息队列:

1.消息队列允许进程以消息的形式交换数据。读写都是针对 整条消息 ,不能读写消息的一部分,不像管道那样可以以流的形式读写任意字节。

2.消息队列除了包含数据外,还有一个整数来表示该消息的类型。读取消息的时候即可以按照 先进先出 方式读取,也可以按照 消息类型 来读取。

二.函数接口                                            

1.创建一个消息队列

1 #include <sys/msg.h>
2 
3 int msgget(key_t key, int msgflg);

key:是一个整数,该函数会将key转换成一个IPC标识符。key有3种方法定义:1.手动随意指定一个整数。2.把IPC_PRIVATE当作key传入,系统会自动生成。3.用fotk()函数。

msgflg:指定该消息的权限,跟文件的权限控制类似。

2.发送消息

1 #include <sys/msg.h>
2 
3 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid:用msget()获取的id。

mgsp:存储消息的结构指针,下面的mtype就是自定义的消息类型,mtext是消息数据。

1 struct msgbuf {
2                long mtype;       /* message type, must be > 0 */
3                char mtext[1];    /* message data */
4            };

msgsz:消息的大小,对应上面msgbuf里面的mtext。

msgflg:控制消息发送时异常状况,如消息队列满。

3.接收消息

1 #include <sys/msg.h>
2 
3 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msqid:用msget()获取的id,或者已知的消息ID。

msgp,msgsz:同msgsnd()。

msgtyp:接收消息的类型,即msgbuf里面的mtype。但还有别的用法:

如果为0 ,就获取队列中第一个可用消息。

大于0 获取相同类型消息的第一个,即mtype。

小于0 ,获取等于或小于mtype的绝对值第一个消息。等会我们一一做实验。

msgflg:同msgsnd()。

4.消息控制

1 #include <sys/msg.h>
2 
3 int msgctl(int msqid, int cmd, struct msqid_ds *buf);

cmd:有3个选项,IPC_STAT,IPC_SET,IPC_RMID。前2个是获取和设置msgid对应的消息结构体,最后一个是删除消息。

三.简单的例子                                        

1.创建消息队列

 1 /**
 2  * @file msg_create.c
 3  */
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <sys/msg.h>
 9 
10 void err_exit(const char *err_msg)
11 {
12     printf("%s error\n", err_msg);
13     exit(1);
14 }
15 
16 int main(void)
17 {
18     int msg_id = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
19     if (msg_id == -1)
20         err_exit("msgget()");
21 
22     printf("create msg_id:%d\n", msg_id);
23 
24     return 0;
25 }

2.发送消息

 1 /**
 2  * @file msg_send.c
 3  */
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <sys/msg.h>
 9 
10 #define MAX_BUFFER 1024
11 
12 typedef struct
13 {
14     long msg_type;
15     char msg_text[MAX_BUFFER];
16 } msg_t;
17 
18 void err_exit(const char *err_msg)
19 {
20     printf("%s error\n", err_msg);
21     exit(1);
22 }
23 
24 int main(int argc, char *argv[])
25 {
26     if (argc < 4)
27     {
28         printf("usage: %s msg_id msg_type msg_text\n", argv[0]);
29         exit(1);
30     }
31 
32     int msg_id = atoi(argv[1]);
33     msg_t send_msg;
34     char *text = argv[3];
35     int text_len = strlen(text);
36 
37     send_msg.msg_type = atoi(argv[2]);
38     memcpy((void *)send_msg.msg_text, text, text_len);
39 
40     if (msgsnd(msg_id, &send_msg, text_len, 0) == -1)
41         err_exit("msgsnd()");
42 
43     return 0;
44 }

3.接收消息

 1 /**
 2  * @file msg_recv.c
 3  */
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <sys/msg.h>
 9 
10 #define MAX_BUFFER 1024
11 
12 typedef struct
13 {
14     long msg_type;
15     char msg_text[MAX_BUFFER];
16 } msg_t;
17 
18 void err_exit(const char *err_msg)
19 {
20     printf("%s error\n", err_msg);
21     exit(1);
22 }
23 
24 int main(int argc, const char *argv[])
25 {
26     if (argc < 3)
27     {
28         printf("usage: %s msg_id msg_type\n", argv[0]);
29         exit(1);
30     }
31 
32     int msg_id = atoi(argv[1]);
33     msg_t recv_msg;
34     long msg_type = atoi(argv[2]);
35 
36     if (msgrcv(msg_id, &recv_msg, MAX_BUFFER, msg_type, 0) == -1)
37         err_exit("msgrcv()");
38 
39     printf("receive:%s\n", recv_msg.msg_text);
40 
41     //if (msgctl(msg_id, IPC_RMID, 0) == -1)
42     //    err_exit("msgctl()");
43 
44     return 0;
45 }

四.实验                                                   

1.创建消息 ,编译执行msg_create.c,用ipcs -q查看消息:

可以看到:msqid就是用IPC_PRIVATE当作key传入,系统会自动生成的, msqid=262144 等会接收消息要用。perms是我们代码设置的权限,此时的消息字节和消息数都是0。

2.发送消息 ,编译执行msg_send.c,并发消息,用ipcs -q查看消息:

上面./mes_send后面依次是:刚刚创建的 消息队列id,消息类型,消息数据

接下来,我们再继续发送1条1类型消息,2条2类型消息,2条3类型消息,等会接收消息做实验。

现在我们有6条消息了。

3.接收消息 ,编译msg_recv.c。我们主要来实验msgrcv()里面的msg_type参数。即该文件的第36行代码。

3.1: 当msg_type等于0时 ,获取队列中第一个可用消息。

可以看到,1234就是我刚刚第一次发送到该队列的消息。

3.2: 当msg_type大于0 ,获取具有相同类型的第一个消息:

上面我们获取的是3类型的消息,接收的刚好是第一次发送3号消息的haha。

3.3: 当msg_type小于0 ,获取等于或小于msg_type绝对值的第一个消息:

上面,-3的绝对值是3,而队列中存在最先放进去的消息是1号消息22222(本来是1号的1234,刚刚我们做实验时读取走了,所以剩下它第一)。1小于3,所以1号消息被读取。

4.消息队列的删除 ,msg_recv.c里面第41行代码,如果放开后编译执行,收到一条消息后整个队列全部删除。

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章