zoukankan      html  css  js  c++  java
  • Linux进程间通信——使用System V 消息队列

    消息队列

    消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
    Linux用宏MSGMAXMSGMNB来限制一条消息的最大长度和一个队列的最大长度。

    在Linux中使用消息队列

    Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信。

    msgget 函数

    创建和访问一个消息队列 :

    原型

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    int msgget(key_t key, int msgflag);
    

    参数

    key:某个消息队列的名字,用ftok()产生
    msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。

    返回值

    成功返回一个非负整数,即消息队列的标识码,失败返回-1。

    ftok 函数

    原型

    #include <sys/types.h>
    #include <sys/ipc.h>
    
    key_t ftok(const char *pathname, int proj_id);
    

    调用成功返回一个key值,用于创建消息队列,如果失败,返回-1。

    msgctl 函数

    消息队列的控制函数

    原型

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

    参数

    msqid:由msgget函数返回的消息队列标识码
    cmd:有三个可选的值,在此我们使用IPC_RMID

    IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
    IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
    IPC_RMID 删除消息队列
    

    返回值

    成功返回0,失败返回-1。

    msgsnd 函数

    把一条消息添加到消息队列中

    原型

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

    参数

    msgid:由msgget函数返回的消息队列标识码
    msgp:指针指向准备发送的消息
    msgze:msgp指向的消息的长度(不包括消息类型的long int长整型)
    msgflg:默认为0

    返回值

    成功返回0,失败返回-1

    消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型

    struct msgbuf
    {
         long mtye;
         char mtext[1];
    };
    

    msgrcv 函数

    是从一个消息队列接受消息

    原型

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); 
    

    参数

    与msgsnd相同

    返回值

    成功返回实际放到接收缓冲区里去的字符个数,失败返回-1

    常用命令

    显示IPC资源

    ipcs -q
    

    手动删除IPC资源

    ipcrm
    

    消息最大长度上限(MSGMAX)

    cat /proc/sys/kernel/msgmax
    

    系统上消息队列的总数上限(MSGMNI)

    cat /proc/sys/kernel/msgmni
    

    每个消息队列的总的字节数(MSGMNB)

    cat /proc/sys/kernel/msgmnb
    

    代码示例

    定义一个 msgque.h 文件

    #ifndef __MSGQUE__H__
    #define __MSGQUE__H__
    
    #ifdef __cplusplus 
    extern "C"
    {
    #endif
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <termios.h>
    #include <getopt.h>
    #include <stdint.h>
    #include <sys/stat.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <pthread.h>
    #include <poll.h>
    #include <sys/msg.h>
    
    
    
    #define MAXLEN 1024
    #define MSG_KEY_DIR "/tmp"
    
    
    typedef struct 
    {
        long Type; 
        char Content[MAXLEN];
    }MsgInfo;
    
    int CreateMessage(const char*pathname,int proj_id);
    int GetMessage(const char*pathname,int proj_id);
    int SendMessage(int msgid,const char* msg,int type);
    int ReceiveMessage(int msgid,char* msg,int type);
    int DestoryMessage(int msgid);
    
    
    
    #ifndef MSG
    #define MSG(fmt...)   
        do {
            printf("{%s}-[%s]-%d: ", __FILE__,__FUNCTION__, __LINE__);
            printf(fmt);
        }while(0)
    #endif
    
    
    #ifdef __cplusplus 
    }
    #endif
    
    #endif
    

    定义 msgque.c 文件

    # include "msgque.h"
    
    
    
    int CreateMessage(const char*pathname,int proj_id)
    {
    	key_t key = ftok(pathname,proj_id);
    	int ret = 0;
    	   
        if((ret=msgget(key,IPC_CREAT|0666))==-1)
        {
            perror("Message Create Error:  
    ");  
    		return -1;		
        }
    	
        return ret;
    }
    
    
    int GetMessage(const char*pathname,int proj_id)
    {
    	key_t key = ftok(pathname,proj_id);
    	int ret = 0;
    	   
        if((ret=msgget(key,IPC_CREAT))==-1)
        {
            perror("Message Get Error:  
    ");  
    		return -1;		
        }
    	
    	return ret;
    }
    
    
    int SendMessage(int msgid,const char* msg,int type)
    {
        MsgInfo buf;
        buf.Type = type;            
        strcpy(buf.Content,msg);       
        if(msgsnd(msgid,&buf,sizeof(buf.Content),0) == -1)
        {
            MSG("Msg Send Error
    ");
            DestoryMessage(msgid);
            return -1;
        }
    
        return 0;
    }
    
    int ReceiveMessage(int msgid,char* msg,int type)
    {
        MsgInfo buf;
        if(msgrcv(msgid,&buf,sizeof(buf.Content),type,0)==-1)
        {
            MSG("Msg Recv Error
    ");
            DestoryMessage(msgid);
            return -1;
        }
        strcpy(msg,buf.Content);
        
        return 0;
    }
    
    int DestoryMessage(int msgid)
    {
        if(msgctl(msgid,IPC_RMID,NULL) == -1)
        {
            MSG("Msg Destroy Error
    ");
            return -1;
        }
    
        return 0;
    }
    
    
    int MessageCommon(key_t key,int flag)
    {
        int ret = 0;
        if((ret=msgget(key,flag))==-1)
        {
            perror("MessageCommon Error:  ");                
        }
        return ret;
    }
    

    定义send.c 文件

    # include "./msgque/msgque.h"
    
    int main()
    {
        int running = 1;
        char buffer[MAXLEN];
        MsgInfo data;
       
        int masgid = CreateMessage(MSG_KEY_DIR,0x01);   
    
        while(running)
        {
            printf("Enter data : ");
    		fgets(buffer, MAXLEN, stdin);
    
            SendMessage(masgid,buffer,1);
    
            if(strncmp(buffer, "end", 3) == 0)
            {
                DestoryMessage(masgid);
                running = 0;
            }        
    
            usleep(100000);
        }
    
        return 0;
    }
    

    定义recv.c 文件

    # include "./msgque/msgque.h"
    
    int main()
    {
        int running = 1;
        char buffer[MAXLEN];    
    
        int masgid = GetMessage(MSG_KEY_DIR,0x01); 
     
        while(running)
        {
            ReceiveMessage(masgid,buffer,1);
    
            printf("You wrote: %s
    ",buffer);
    
            if(strncmp(buffer, "end", 3) == 0)
            {             
                 running = 0;
            }      
    
            usleep(100000);
        }
    
        exit(EXIT_SUCCESS);
    }
    
    

    测试结果:

  • 相关阅读:
    Java如何编写自动售票机程序
    install windows service
    redis SERVER INSTALL WINDOWS SERVICE
    上传文件
    This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.
    解决Uploadify上传控件加载导致的GET 404 Not Found问题
    OracleServiceORCL服务不见了怎么办
    Access to the temp directory is denied. Identity 'NT AUTHORITYNETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss
    MSSQL Server 2008 数据库安装失败
    数据库数据导出成XML文件
  • 原文地址:https://www.cnblogs.com/chay/p/10798266.html
Copyright © 2011-2022 走看看