版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liu_zhen_kai/article/details/82053214
消息队列的基本模型
消息队列中有两个数据结构
- msqid_ds消息队列数据结构:描述着整个消息队列的属性包括:消息队列的权限,消息队列的拥有者,指向消息队列第一个以及最后一个成员的指针
- msg消息队列的主体数据结构包括:消息类型,消息大小,消息位置以及下一消息。
60 #define MSG_MEM_SCALE 32
61
62 #define MSGMNI 16 /* <= IPCMNI */ /* max # of msg queue identifiers */
63 #define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */
64 #define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */
在centos 6.5中规定:
- 默认情况下系统最多存在16个消息队列
- 每个消息队列最大为16384个字节
- 消息队列的每个节点最大为8192个字节
Linux消息队列管理
1.在使用一个消息队列之前,需要用msgget函数来创建一个消息队列,函数如下:
int msgget(key_t key, int msgflg);
参数分析
key:
系统为每个ipc机制都分配了唯一的ID,可以自己定义,或者由ftok函数来获取,
只要任意进程用到相同的ID,即可实现进程间通信。
msgflg:
其中可以选择:IPC_CREAT:如果key不存在,就创建一个key,若key存在则返回ID
IPC_EXCL:如果key存在,返回失败
IPC_NOWAIT:如果需要等待,直接返回错误
低位用来确定访问权限,最终值为perm&umask,与|选项一起使用
返回值:
返回一个msqid,即为key的句柄
2.消息队列属性控制用msgctl函数来实现
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数分析
msqid:key的操作句柄,一般为msgget的返回值
cmd:执行的控制命令,包括选项有:
IPC_STAT:读取消息队列属性,并将msqid__ds结构体信息放入buf中
IPC_SET:读取消息队列属性,按buf中的值设定消息队列中去设定所属用户,所属组,权限等信息
IPC_RMID:删除消息队列
IPC_INFO:读取消息队列的
buf:
msqid_id结构体类型变量,用于储存信息或者修改消息队列信息
返回值:
大多数成功返回0,失败返回-1
3.发送消息到消息队列msgsnd函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数分析:
msqid:
消息队列的句柄,即要发送到的消息队列
msgp:
指向用户定义的缓冲区,是一个需要在使用时自己定义的数据结构
struct msgbuf{
long mtype;//消息类型
char mtext[1];//消息内容
};
msgsz:
发出信息的大小。
msgflg:
用来指定在达到系统为消息队列规定的边界时所采取的操作
1.IPC_NOWAIT:如果需要等待,则不发送消息直接返回,错误信息:EAGAIN
2.如果设置为0,则阻塞调用进程
4.从消息队列接受信息msgrcv
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
参数分析:
msqlid:
函数从消息队列msqid中接收信息。
msgp:
从消息队列接收的信息放入msgp当中
msgsz:
用于指定mtext的大小,收到的消息大于msgsz并且msgflg&MSG_NOERRER为真,则
截取部分将丢失。
msgtyp用于指定接收到的消息的类型,具体如下:
1.等于0:接收队列中第一条消息,任意类型
2.大于0:接收队列中第一条为这个类型的消息
3.小于0:接收第一条最低消息
msflg:
为设置选项
消息队列的应用实例
用消息队列来实现一个聊天程序
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/ipc.h>
9 #include <sys/msg.h>
10
11 struct msgbuf{
12 int type;
13 char ptr[0];
14 };
15
16 int main(int argc, char* argv[])
17 {
18 key_t key = ftok(argv[1], 100);
19 int msgid;
20 msgid = msgget(key, IPC_CREAT|0644);//找到key的句柄
21 pid_t pid = fork();
22 if(pid < 0)
23 {
24 perror("fork"),
25 exit(1);
26 }
27 else if(pid == 0)//子进程发送消息
28 {
29 while(1){
30 printf("please input msg:");
31 char buf[128];
32 fgets(buf, 128, stdin);
33 struct msgbuf* ptr = (struct msgbuf*)malloc((sizeof(struct msgbuf) + strlen(buf) + 1));
34 ptr->type = 1;
35 memcpy(ptr->ptr, (const char*)buf, strlen(buf) + 1);
37 msgsnd(msgid, ptr, strlen(buf) + 1, 0);
38 free(ptr);
39 }
40 }
41 else
42 {
43 struct msgbuf{
44 int type;
45 char ptr[1024];
46 };
47 while(1){
48 struct msgbuf msgbuf;
49 memset(&msgbuf, '\0', sizeof(msgbuf));
50 msgrcv(msgid, &msgbuf, 1024, 2, 0);
51 printf("%s\n", msgbuf.ptr);
52 }
53 }
54
55 return 0;
56 }
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/ipc.h>
9 #include <sys/msg.h>
10
11 struct msgbuf{
12 int type;
13 char ptr[0];
14 };
15
16 int main(int argc, char* argv[])
17 {
18 key_t key = ftok(argv[1], 100);
19 int msgid;
20 msgid = msgget(key, IPC_CREAT|0644);//找到key的句柄
21 pid_t pid = fork();
22 if(pid < 0)
23 {
24 perror("fork"),
25 exit(1);
26 }
27 else if(pid == 0)//子进程发送消息
28 {
29 while(1){
30 printf("please input msg:");
31 char buf[128];
32 fgets(buf, 128, stdin);
33 struct msgbuf* ptr = (struct msgbuf*)malloc((sizeof(struct msgbuf) + strlen(buf) + 1));
34 ptr->type = 2;
35 memcpy(ptr->ptr, (const char*)buf, strlen(buf) + 1);
36 //收发信息必须由传输结构体完成,结构体就是桥梁
37 msgsnd(msgid, ptr, strlen(buf) + 1, 0);
38 free(ptr);
39 }
40 }
41 else
42 {
43 struct msgbuf{
44 int type;
45 char ptr[1024];
46 };
47 while(1){
48 struct msgbuf msgbuf;
49 memset(&msgbuf, '\0', sizeof(msgbuf));
50 msgrcv(msgid, &msgbuf, 1024, 1, 0);
51 printf("%s\n", msgbuf.ptr);
52 }
53 }
54
55 return 0;
56 }
这样就实现了聊天接收发送,不再是单向传输了。