• Linux进程间通信(System V) --- 消息队列


    消息队列 IPC 原理

    消息队列是消息的链式队列,如下图为消息队列的模型。整个消息队列有两种类型的数据结构。

    1.msqid_ds 消息队列数据结构:描述整个消息队列的属性,主要包括整个消息队列的权限、拥有者、两个重要的指针(分别指向消息队列的第一个消息和最后一个消息)。
    
    2.msg 消息队列数据结构:整个消息队列的主体,一个消息队列有若干个消息,每个消息数据结构的基本成员包括消息类型、消息大小、消息内容指针和下一个消息数据结构的位置。
    

    消息队列还可以基于类型处理,但是,消息队列的 FIFO 原则仅仅适用于同类型的消息。在 Linux 中,对消息队列进行了以下规定(不同 Linux 版本的话值可能会不同):

    1.默认情况下,整个系统最多允许有16个消息队列。
    2.每个消息队列最大为16384字节。
    3.消息队列中的每个消息最大为8192字节。
    

    这些内容在 /usr/include/linux/msg.h 中进行定义:

    #define MSGMNI    16   /* <= IPCMNI */     /* max # of msg queue identifiers */
    #define MSGMAX  8192   /* <= INT_MAX */   /* max size of message (bytes) */
    #define MSGMNB 16384   /* <= INT_MAX */   /* default max size of a message queue */
    
    消息队列的基本属性

    下图出于 /usr/include/linux/msg.h 文件

    消息队列管理

    1.创建消息队列:

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    /* 第一个参数为key值,一般由ftok()函数获得;第二个参数为访问权限 */
    int msgget(key_t key, int msgflg);
    

    2.消息队列属性控制

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    /* 
     * 第一个参数为消息队列ID,由msgget获得
     * 第二个参数为控制指令
     * 第三个参数为数据传递的载体
     */
    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    

    控制指令如下:

    3.发送消息队列

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    /*
     * 第一个参数为消息队列ID
     * 第二个参数 msgp 指向定义的缓冲区
     * 第三个参数为发送消息的大小
     * 第四个参数一般高为0,阻塞调用进程
     */
    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    

    4.从消息队列接收消息

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    /*
     * 第一个参数为消息队列ID
     * 第二个参数为临时消息数据结构,用于储存消息
     * 第三个参数为接收消息的大小
     * 第四个参数用于指定请求的消息类型
     * 第五个参数一般设置为0,阻塞调用进程 
     */
    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
    

    其中消息数据结构应定义如下:

    /* From /usr/include/linux/msg.h */
    
    struct msgbuf {
        long mtype;         /* 消息类型 */
        char mtext[1];      /* 存储消息位置,需要重新定义 */
    };
    
    消息队列应用实例

    创建两个进程,使用消息队列进行通信,一个进程发送消息,另一个进程接收消息。

    发送端:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct msgbuf {
    	long mtype;       
    	char mtext[50];    
    };
    
    int main()
    {
    	int key, msg_id;
    	static struct msgbuf buf;
    
    	key = ftok(".", 1);
    
    	msg_id = msgget(key, IPC_CREAT | 0600);
    
        /* 设置消息的类型 */
    	buf.mtype = 1;
    
    	while(1){
    
    		fgets(buf.mtext, 50, stdin);
    
            /* 输入quit退出进程,并删除队列 */
    		if(!strncmp(buf.mtext, "quit", 4)){
    			//msgctl(msg_id, IPC_RMID, 0);
    			exit(0);
    		}
    
            /* 将消息发送到队列 */
    		msgsnd(msg_id, (void *)&buf, strlen(buf.mtext)+1, 0);
    	}
    
    	return 0;
    }
    

    接收端:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    struct msgbuf {
    	long mtype;       
    	char mtext[50];    
    };
    
    int main()
    {
    	int key, msg_id;
    	static struct msgbuf buf;
    
    	key = ftok(".", 1);
    
    	msg_id = msgget(key, IPC_CREAT | 0600);
    
        /* 设置消息类型 */
    	buf.mtype = 1;
    
    	while(1){
    
            /* 从消息队列接收消息 */
    		msgrcv(msg_id, (void*)&buf, sizeof(buf), buf.mtype, 0);
    		
    		printf("Recv msg : %s 
    ", buf.mtext);
        }
    
    	return 0;
    }
    

    运行结果:

    删除消息队列:

    ipcrm -q msqid
    
  • 相关阅读:
    ASP.NET面试题(二)
    iBatis.Net系列(四) iBatisNet API基础
    ibatisnet系列(一) 总览
    iBatisnet系列(二) 配置运行环境和日志处理
    HDU 1575 Tr A (矩阵乘法)
    HDU 连连看
    1504: ZZ的橱柜 (优先队列)
    离散化思想
    POJ 2777 Count Color (线段树)
    POJ 1823 Hotel (线段树)
  • 原文地址:https://www.cnblogs.com/GyForever1004/p/8419056.html
Copyright © 2020-2023  润新知