Linux ipc System V 消息队列

Linux ipc System V 消息队列

消息队列提供了从一个进程向另一个进程发送有类型数据块的方法。

消息队列由操作系统内核提供,可以同时被两个进程同时看到。

每个数据块都被认为是有一个类型值的,接受者可以接受不同种类型的值。

每个消息对列的最大长度是有上限的(MSGMAX),每个消息队列的总字节数是有上限的(MSGMNB),系统上消息队列的总数也是有上限的(MSGMNI)。

I P C 标识符:每一个内核中的IPC结构(消息队列,信号量,共享存储段)都用一个非负整数的标识符(identifier)加以引用。当一个消息队列发送或取消息,只需要知道其队列标示符。

// 内核为每个IPC对象维护一个数据结构(/usr/include/linux/ipc.h)
struct ipc_perm
{
    key_t __key; /* key supplied to xxxget(2) */
    //每一个ipc结构都有一个唯一的表示符,其值不重要,重要的是其具有唯一性,使用消息队列的双方,通过_key来找到该消息队列
    uid_t uid;  /* Effective UID of owner */
    gid_t gid;  /* Effective GID of owner */
    uid_t cuid; /* Effective UID of creator */
    gid_t cgid; /* Effective GID of creator */
    unsigned short mode;  /* Permission */  //权限
    unsigned short __seq; /* Sequeence number*/
}

获取_key值的两种方法:

  • IPC_PRIVATE :/由操作系统指定
  • 通过ftok()获取_key值

ftok()函数

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

//ftok 函数把一个已存在的路径名和一个整数标识转换成一个key_t值,即IPC关键字
//path 参数就是你指定的文件名(已经存在的文件名),一般使用当前目录。当产生键时,只使用id参数的低8位。
//id 是子序号, 只使用8bit (1-255)
//返回值:若成功返回键值,若出错返回(key_t)-1 
//在一般的UNIX实现中,是将文件的索引节点号取出(inode),前面加上子序号的到key_t的返回值
//消息队列的结构 ( /usr/include/linux/msg.h)
// message queue id
// defined in <linux/ipc.h>
struct msqid_ds
{
    struct ipc_perm msg_perm;
    struct msg* msg_first; //队头     /* first message on queue, unused */
    struct msg* msg_last; //队尾      /* last message 
    in queue, unused */
    __kernel_time_t msg_stime;  /* last msgsnd time */
    __kernel_time_t msg_rtime;  /* last msgrcv time */
    __kernel_time_t msg_ctime;  /* last change time */
    unsigned long msg_lcbytes;  /* Reuse junk fields for 32 bit */
    unsigned long msg_lqbytes;  /* ditto  == 同上... */
    unsigned short msg_cbytes;  /* current number of butes on queue */
    unsigned short msg_qnum;    /* number of messages in queue */
    __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
    __kernel_ipc_pid_t msg_lrpid; /* last receive pid */
}

消息队列函数
msgget函数
//创建和访问一个消息队列
#include <sys/msg.h>
#include <sys/ipc.h>
int msgget(key_t key, int msgflag);

//参数:
  //key 使用ftok生成的标识队列唯一性的键值  
  msflg:由九个权限标志构成,它们的用法与创建文件时的mode模式标志一样
  
  
  当IPC_CREAT和IPC_EXCL同时被使设置:若消息队列不存在,则创建一个全新的消息队列,如果存在则出错返回
  
  当IPC_CREAT单独使用时,如果消息队列不存在则新建一个,如果存在则打开
  
  
  IPC_EXCL单独使用无意义
  
  
  
  通过|使用  也可以与权限|在一起
  
  //返回值:成功返回一个非负整数,及消息队列的表示码(不是key),失败返回-1;

msgctl函数

//消息队列控制函数

int msgctl(int msgqid,int cmd,struct  msgqid_ds *buf)
参数:msgqid:由msgget返回的消息队列标识码
cmd:将要采取的动作
//返回值:成功返回0,失败返回-1

cmd采取的三个操作

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

msgsnd函数

//把一条消息添加到消息队列中
int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg);
参数:
   msqid: msgget函数返回的标识码
   msgp: 指向准备发送信息的指针
   msgsz: msgp指向消息的长度,不包含保存消息类型的long int 的长度
    msgflg=IPC_NOWWAIT表示队列不满

由系统提供的消息结构
struct msgbuf{
    long mtype;
    char mtext[1];//数组的大小可以任意设置
}


//消息结构必须小于系统规定的上限值
//必须以一个long int长整数开始,接收函数利用这个长整数确定消息的类型

msgrcv函数


ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int msgflag);

//msgsz:消息的大小
//ptr :指向一个长整形数,将返回的消息类型存储在//其中(即结构体 struct msgbuf 的mtype成员)
//nbyte :是存放实际消息数据的缓冲区的长度
//type :可以指定想要哪一种消息 

  /* type == 0 返回队列的第一个消息
 type > 0 返回队列中消息类型type的第一个消息
 type < 0  返回队列中消息类型值小于或等于type绝对值的消息,如果这种消息有若干个,则类型值最小的消息*/
msgflag:消息类型,这个参数是控制函数行为的标识。取值可以是0,标识忽略。 
IPC_NOWAIT:如果消息队列为空,则返回一个ENOMSG,并将控制权交回给调用函数的进程。如果不指定这个参数,那么进程将被阻塞知道函数可以从队列中取得符合条件的消息为止。

0  表示不关心,忽略此行为

返回值:成功执行返回消息的数据部分的长度,若出错则返回-1 

msgrcv成功执行时,内核更新与该消息队列相关联的msqid_ds结构以指示调用者的进程ID(msg_lrpid)和调用时间(msg_rtime),并将队列中的消息数(msg_qnum)减1。*

查看消息队列&&删除消息队列

  • ipcs -q //查看消息队列
  • ipcrm -q msgid //删除一个消息队列
[wens@MiWiFi-R1CL-srv msgqueue]$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x6603b8fa 262144     wens       644        0            0           

[wens@MiWiFi-R1CL-srv msgqueue]$ ipcrm -q 262144
[wens@MiWiFi-R1CL-srv msgqueue]$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
//键值    //消息队列标识码       //权限    //数据量     //消息条数

消息队列创建实例:实现client&&server间的通信

github 实例链接

1                                             
  2 .PHONY:all                                
  3 all:client server                         
  4                                           
  5                                           
  6 client:client.c common.c                  
  7   gcc -o $@ $^                            
  8 server:server.c common.c                  
  9   gcc -o $@ $^                            
 10 .PHONY:clean                              
 11 clean:                                    
 12   rm -f client server all     

common.h

 1 #ifndef __COMMON_H_                                     
    2 #define __COMMON_H_                                     
    3                                                         
    4                                                         
    5 #include <stdio.h>                                      
    6 #include <unistd.h>                                     
    7 #include <stdlib.h>                                     
    8 #include <string.h>                                     
    9 #include <sys/types.h>                                  
   10 #include <sys/stat.h>                                   
   11                                                         
   12 #include <sys/ipc.h>                                    
   13 #include <sys/msg.h>                                    
   14                                                         
   15 #define PATHNAME "."  //ftok 的路径参数设置为当前路径   
   16 #define PROJ_ID   0x666     //ftok 的另一个参数         
   17 #define SERVER_TYPE 1                                   
   18 #define CLIENT_TYPE 2                                   
   19                                                         
E> 20 struct msgbuf                                           
   21 {                                                       
   22   long mtype;                                           
   23   char mtext[1024];                                     
   24 };                                                      
   25                                                         
   26 int creatMsgque();  //创建消息队列                      
   27 int getMsgque();  //打开消息队列                        
   28 int destoryMsg(int msgid);  //删除一个消息队列          
   29 int sendMsg(int msgid,const void* msgp,int type);//向消>
      息对列中添加消息                                        
   30 int recvMsg(int msgid,void* str,int type);              
   31 #endif  

common.c

 1 #include "common.h"                                     
    2                                                         
    3 static int commonsqueue(int flags)//将该函数设置为静态外
      部不可见                                                
    4 {                                                       
    5                                                         
    6   key_t _key=ftok(PATHNAME,PROJ_ID);  //生成key值       
    7  if(_key<0)                                             
    8  {                                                      
    9   perror("ftok error");                                 
   10   exit(1);                                              
   11  }                                                      
   12                                                         
   13  int msgid=msgget(_key,flags|0644);  //创建一个消息队列 
   14   if(msgid<0)                                           
   15   {                                                     
   16     perror("msgid error");                              
   17     return -1;                                          
   18   }                                                     
   19                                                         
   20                                                         
   21  return msgid;  //返回创建队列后的识别码                
   22                                                         
   23 }                                                       
   24                                                         
   25 int creatMsgque()  //创建消息队列                       
   26 {                                                       
   27    return commonsqueue(IPC_CREAT|IPC_EXCL);             
   28                                                         
   29 }                                                       
   30 int getMsgque()                                         
   31 {                                                       
   32   return commonsqueue(IPC_CREAT);//仅用于打开一个消息队>
      列                                                      
   33 }//打开消息队列                                         
   34 int destoryMsg(int msgid)//删除一个消息队列             
   35 {                                                       
   36                                                         
   37    if(  msgctl(msgid,IPC_RMID ,NULL ) <0) //第三个参数表
      示不需要队列的属性信息                                  
   38    {   
    39      perror("delete error");                            
   40      return -1;                                         
   41    }                                                    
   42 }                                                       
   43                                                         
   44                                                         
   45 int sendMsg(int msgid,const void* msgp,int type)//向消息
      对列中添加消息                                          
   46 {                                                       
   47                                                         
   48   struct msgbuf buf;                                    
   49   buf.mtype=type;                                       
E> 50   strcpy(buf.mtext,msgp);                               
   51   if( msgsnd (msgid,(void*)&buf,sizeof(buf.mtext),0)<0) 
   52   {                                                     
   53     perror("senmsg error");                             
   54     return -1;                                          
   55   }                                                     
   56 }                                                       
   57                                                         
   58                                                         
   59                                                         
   60                                                         
   61 int recvMsg(int msgid,void* str,int type)//从消息队列中>
      取消息                                                  
   62 {                                                       
   63   struct msgbuf buf;                                    
   64   if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),type,0 )
      <0)                                                     
   65   {                                                     
   66     perror("receive msg error");                        
   67     return -1;                                          
   68   }
E> 69   strcpy(str,buf.mtext);
   70   return 0;
   71 }
   72 

server.c

 1 #include "common.h"                                       
  2                                                           
  3 int main()                                                
  4 {                                                         
  5                                                           
  6                                                           
  7  int msgid=creatMsgque();                                 
  8                                                           
  9  char buf[1024];                                          
 10                                                           
 11  while(1)                                                 
 12  {                                                        
 13      buf[0]=0;                                            
 14     recvMsg(msgid,buf,CLIENT_TYPE);                       
 15       if(strcmp(buf,"exit")==0)                           
 16       {                                                   
 17         printf("client quit\n");                          
 18         break;                                            
 19       }                                                   
 20     printf("client # %s \n",buf);                         
 21     printf("please enter # ");                            
 22     fflush(stdout);                                       
 23     ssize_t s=read(0,buf,sizeof(buf)-1);                  
 24     if(s>0)                                               
 25     {                                                     
 26       buf[s-1]=0;//消除回车并以'\0’结尾                   
 27       sendMsg(msgid,buf,SERVER_TYPE);                     
 28     }                                                     
 29     else if(s<0)                                          
 30     {                                                     
 31       perror("sendmsg error");                            
 32       break;                                              
 33     }                                                     
 34  }                                                        
 35    destoryMsg(msgid);                                     
 36   return 0;                                               
 37 }                  

client.c

 1 #include "common.h"                                       
  2                                                           
  3 int main()                                                
  4 {                                                         
  5 char buf[1024];                                           
  6                                                           
  7 int msgid=getMsgque();                                    
  8                                                           
  9 while(1)                                                  
 10 {                                                         
 11                                                           
 12    printf("please enter # ");                             
 13    fflush(stdout);                                        
 14    ssize_t s=read(0,buf,sizeof(buf)-1);                   
 15    if(s>0)                                                
 16    {                                                      
 17       buf[s-1]=0;  //消除在发送信息时输入的回车符         
 18                                                           
 19   sendMsg(msgid,buf,CLIENT_TYPE);                         
 20 if(strcmp(buf,"exit")==0)                                 
 21   {                                                       
 22     break;                                                
 23   }                                                       
 24    }else if(s<0){                                         
 25                                                           
 26      perror("read error\n");                              
 27     exit(1);                                              
 28    }                                                      
 29 recvMsg(msgid,buf,SERVER_TYPE);                           
 30   printf("server # %s\n",buf);                            
 31 }                                                         
 32   return 0;                                               
 33 }                  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值