zoukankan      html  css  js  c++  java
  • Linux:进程通信之消息队列Message实例

    /*send.c*/  

    /*send.c*/  
    #include <stdio.h>   
    #include <sys/types.h>   
    #include <sys/ipc.h>   
    #include <sys/msg.h>   
    #include <errno.h>   
    
    #define MSGKEY 1024   
      
    struct msgstru  
    {  
       long msgtype;  
       char msgtext[2048];   
    };  
      
    main()  
    {  
      struct msgstru msgs;  
      int msg_type;  
      char str[256];  
      int ret_value;  
      int msqid;  
      
      msqid=msgget(MSGKEY,IPC_EXCL);  /*检查消息队列是否存在*/  
      printf("msqid:%d 
    ",msqid);  
      if(msqid < 0){  
        msqid = msgget(MSGKEY,IPC_CREAT|0666);/*创建消息队列*/  
         printf("msqid:%d 
    ",msqid);  
        if(msqid <0){  
        printf("failed to create msq | errno=%d [%s]
    ",errno,strerror(errno));  
        exit(-1);  
        }  
      }   
       
      while (1){  
        printf("input message type(end:0):");  
        scanf("%d",&msg_type);  
        if (msg_type == 0)  
           break;  
        printf("input message to be sent:");  
        scanf ("%s",str);  
        msgs.msgtype = msg_type;  
        strcpy(msgs.msgtext, str);  
        /* 发送消息队列 */  
    	printf("msqid:%d,msgs.msgtext: %s,size:%d
    ",msqid,msgs.msgtext,sizeof(msgs.msgtext));
        ret_value = msgsnd(msqid,&msgs,sizeof(struct msgstru),IPC_NOWAIT); 
        printf("sendXxdl(),ret_value:%d,sizeof(struct msgstru):%d 
    ",ret_value,sizeof(struct msgstru)); 
        if ( ret_value < 0 ) {  
           printf("msgsnd() write msg failed,errno=%d[%s]
    ",errno,strerror(errno));  
           exit(-1);  
        }  
      }  
      msgctl(msqid,IPC_RMID,0); //删除消息队列   
    }
    

    /*receive.c */

    /*receive.c */  
    #include <stdio.h>   
    #include <sys/types.h>   
    #include <sys/ipc.h>   
    #include <sys/msg.h>   
    #include <errno.h>   
      
    #define MSGKEY 1024   
      
    struct msgstru  
    {  
       long msgtype;  
       char msgtext[2048];  
    };  
      
    /*子进程,监听消息队列*/  
    void childproc(){  
      struct msgstru msgs;  
      int msgid,ret_value;  
      char str[512];  
        
      while(1){  
         msgid = msgget(MSGKEY,IPC_EXCL );/*检查消息队列是否存在 */  
         if(msgid < 0){  
            printf("msq not existed! errno=%d [%s]
    ",errno,strerror(errno));  
            sleep(2);  
            continue;  
         }  
         /*接收消息队列*/  
         ret_value = msgrcv(msgid,&msgs,sizeof(struct msgstru),0,0);  
         printf("text=[%s] pid=[%d]
    ",msgs.msgtext,getpid());  
      }  
      return;  
    }  
      
    void main()  
    {  
      int i,cpid;  
      printf("open receive
    ");  
      /* create 5 child process */  
      for (i=0;i<1;i++){  
         cpid = fork();  
         if (cpid < 0)  
            printf("fork failed
    ");  
         else if (cpid ==0) /*child process*/  
            childproc();  
      }  
    }
    


    实现linux进程通信的方式有5种:
    --信号(Singal)
    --管道(Pipe)
    --消息队列(Message)
    --信号量(Semaphore)

    消息队列
    一、概念
    消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向中按照一定的规则添加新消息;有读权限的进程则可以读走消息。读走就没有了。消息队列是随内核持续的。 只有内核重启或人工删除时,该消息才会被删除。在系统范围内,消息队列与键值唯一对应。

    消息队列的数据结构
    1.struct msqid_ds *msgque[MSGMNI]向量:
    msgque[MSGMNI]是一个msqid_ds结构的指针数组,每个msqid_ds结构指针代表一个系统消息队列,msgque[MSGMNI]的大小为MSGMNI=128,也就是说系统最多有MSGMNI=128个消息队列
    2.struct msqid_ds
    一个消息队列结构
    struct msqid_ds 中主要数据成员介绍如下:
    struct msqid_ds
    {
    struct ipc_perm msg_perm;
            struct msg *msg_first;                                     /*消息队列头指针*/
            struct msg *msg_last;                                     /*消息队列尾指针*/
            __kernel_time_t msg_stime;                          /*最后一次插入消息队列消息的时间*/
            __kernel_time_t msg_rtime;                          /*最后一次接收消息即删除队列中一个消息的时间*/
            __kernel_time_t msg_ctime; 
            struct wait_queue *wwait;                                /*发送消息等待进程队列*/
            struct wait_queue *rwait;  
            unsigned short msg_cbytes;
            unsigned short msg_qnum;                             /*消息队列中的消息个数*/
            unsigned short msg_qbytes;
            __kernel_ipc_pid_t msg_lspid;                        /*最后一次消息发送进程的pid*/
            __kernel_ipc_pid_t msg_lrpid;                         /*最后一次消息发送进程的pid*/
    };
    3.struct msg 消息节点结构:
    msqid_ds.msg_first,msg_last维护的链表队列中的一个链表节点
    struct msg
    {
           msg *msg_next;              /*下一个msg*/
           long msg_type;                /*消息类型*/
           *msg_spot;                       /*消息体开始位置指针*/
            msg_ts;                           /*消息体长度*/
            message;                     /*消息体*/
    }
    4.msgbuf消息内容结构:
    msg 消息节点中的消息体,也是消息队列使用进程(消息队列发送接收进程)发送或者接收的消息
    struct msgbuf
    {
            long mtype;        --消息类型
            char mtext[n];     --消息内容
    }


    二、步骤及思路
    1、取得键值
    2、打开、创建消息队列
    3、发送消息
    4、接收消息
    下面具体看看:
    1、取得键值
          key_t ftok(char *pathname, char proj)
    头文件为<sys/ipc.h>。返回文件名对应的键值,失败返回 -1。proj是项目名,随便写,不为0就行。
    fname就是你指定的文件名(已经存在的文件名)。需要有-t 的权限,或用root权限执行,通常设为/tmp或设为" . "。这里我感觉不用这个函数也行,因为key值可以自己指定,例如: #define KEY_MSG 0x101
    2、打开、创建消息队列
         int msgget(key_t key, int msgflg)
    头文件为<sys/msg.h>。key由ftok获得。
    msgflg有:
    IPC_CREAT 创建新的消息队列,应配有文件权限0666。
    IPC_EXCL  与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误。
    IPC_NOWAIT 读写消息不阻塞。
    当没有与key相对应的消息队列并且msgflg中包含了IPC_CREAT标志 或 key的参数为IPC_PRIVATE 时,创建一个新的消息队列。
    3、发送消息
             int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
    向消息队列发送一条消息。msqid为消息队列的id,msgp为存放消息的结构体。msgsz是消息的长度,和数组的大小不一样哦。msgflg为消息标志,通常为0,也可以为IPC_NOWAIT。出错返回 -1。
    消息格式
          struct msgbuf  {
                       long mtype;
                       char mtext[100];
          };
    4、接收消息
    int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg)
    从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指定的msgbuf结构中。读取后队列中的消息将会删除。size为结构体中数据的大小,不要计算msgtyp。出错返回 -1。


  • 相关阅读:
    用Java socket (TCP通信模型)实现一个简单的web 服务器
    java.net.BindException: 权限不够
    java 反射机制探究
    java程序执行顺序
    python 安装第三方库,超时报错--Read timed out.
    RTTI和反射
    Ubuntu 16.04
    20160515-hibernate--事务
    Ubuntu 16.04
    python--继承和多态
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300902.html
Copyright © 2011-2022 走看看