Linux进程通信之消息队列

本文深入探讨了Linux消息队列的概念、创建、使用方法及实例程序,包括消息队列函数msgget、msgsnd、msgrcv、msgctl的详细解析与应用。

Linux进程通信之消息队列

        消息队列就是一个消息的链表,我们可以把消息看作一个记录,具有特定的格式。消息队列也是进程中通信常见的方式之一,进程可以向消息队列中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。下面我们就来看看常见的消息队列函数:

(1)   创建或打开一个消息队列

int msgget(key_t key , intflag);

消息队列的通信编程与我前面学的信号量、共享内存差不多,都属于IPC结构,我们创建一个消息队列其实也就是创建一个消息队列的标识符。msgget的两个参数应该是非常清楚的,因为在我们的共享内存和信号量都会用到这两个参数,第一个就是我们的键值,用于产生我们的标识符,第二个参数是一个标志,指定消息队列的属性和权限。

该函数成功执行后就返回消息队列ID,以后我们就可以根据这个ID来访问这个消息队列。

(2)   将数据放到消息队列中

int msgsnd(int mspid , const void *ptr, size_t  nbytes , int flag);

这个函数的参数有点多,我们来一一介绍一下

mspid:这个参数就是我们前面用msgget函数返回的消息队列的ID。

prt: prt参数指向一个准备发送消息的结构,这个结构如下:

struct mymesg
{
   long mtype;
char mtext[512];
}

该结构必须包含一个长整型成员变量,用来标志这个消息的类型。第二个成员就用来指定存放我们消息。

nbytes: 消息长度(不包括长整型成员变量的长度)。

flag:一般指定为IPC_NOWAIT,表示非阻塞状态。

该函数成功执行时返回0,否则返回-1。

(3)从消息队列中获取消息

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

该函数的参数更多,不过大部分与msgget函数的参数类似。

msqid :消息队里的ID。

prt:与msgget一样。

nbytes:获取消息的长度。

type: 获取消息的类型,上面我们说过prt指向的结构体,有一个参数是指定消息的类型,我们在获取消息时,就要指定这个类型。如果type为0,就获取队列中的第一个消息。如果它的值大于0,将获取指定类型的消息,如果小于0,就获取类型等于或者小于type的绝对值的第一个消息。

flag:一般指定为IPC_NOWAIT。

该函数执行成功后返回消息的数据部分的长度,以字节为单位,否则返回-1。

需要说明的是,从msqid代表的消息队列中读取一个type类型的消息,并把消息存储在msgbuf结构中,在成功地读取了一条消息以后,队列中的这条消息将被删除。

(4)控制消息队列

       int msgctl(int msgid , int command , struct msgid_ds *buf);

该函数用来控制消息队列,它与共享内存的shmctl函数类似,其参数意义为:

msgid: 为获取消息队列的标识符。

command:该参数说明对由msgid指定的队列要执行的命令:

   IPC_STAT:取此队列的msqid_ds结构,并将它存放在buf指向的结构中。

   IPC_SET:按由buf指向结构中的值,设置该队列的msqid_ds结构,不过该命令需要有足够的权限才能执行。

   IPC_RMID:删除消息队列。

buf:是指向msgid_ds结构的指针,我们知道,在创建一个消息队列的时候,内核为每一消息队列都会指定一个关联结构,该结构包含了该消息队列的相关信息,msgid_ds就是这样的一个结构。

该函数成功时返回0,否则返回-1.

说太多理论的东西可能不太好理解,下面我们就来写一个实例程序,利用消息队列方式实现两个不相关进程间的通信:

 发送进程程序:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
 
#define MAX 256
struct msgbuf
    {
       long int mtype;
       char mtext[MAX]; 
    };
void main()
{
   int mspid;
   key_t key;  
   int ret;
   struct msgbuf mymsg;
  
    //创建一个消息队列,首先获取键值
   key = ftok("/home" , 1);
   mspid = msgget(key ,IPC_CREAT|0666);
   if(mspid==-1)
          {
               printf("creat the queuefailure\n");
               return;     
          }
   
    //向消息队列中填入数据,需要定义一个结构体
   mymsg.mtype = 1;
   strncpy(mymsg.mtext , "it is a memsg_queue test!" , 30);
        ret = msgsnd(mspid , &mymsg , 256 ,IPC_NOWAIT);
       
        if(ret == -1)
           {
               printf("send memsage failure\n");
               return;  
           } 
}

接收进程程序:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
 
struct msgbuf
    {
       long mtype;
       char mtext[256];     
    };
void main()
{
       int msqid;
   key_t key;  
   int size;
   struct msgbuf mymsg;
  
    //获取一个消息队列,首先获取键值
   key = ftok("/home" , 1);
   msqid = msgget(key ,IPC_CREAT|0666);
   if(msqid==-1)
          {
               printf("creat the queuefailure\n");
               return;     
          }
           
            //读取一个消息队列中的内容
   msgrcv(msqid , &mymsg ,sizeof(mymsg.mtext),1 , IPC_NOWAIT);
   printf("the msg is : %s\n",mymsg.mtext);
   
    //删除消息队列
   if( msgctl(msqid , IPC_RMID , 0) == -1)
           {
               printf("delete the queuefailure\n");
               return;     
           }  
}

        发送进程程序创建一个消息队列,并向其中写入“it is a memsg_queue test!“这条消息语句,接收进程就获取这个消息队列,然后取出其中的消息,并打印出来,程序中关键的地方都有解释,需要注意的就是消息队列结构体的长整型,发送进程和接收进程此值一定要对应,否则读不出要的消息。打开linux命令行,在命令行中编译运行这两个程序,先运行发送进程,然后运行接收进程,可以发现我们的接收进程正确的获取了我们消息队列中的消息。有个细节大家注意没,我们运行发送进程后,在运行接收进程可以接收到消息,然后再运行我们的接收进程却收不到消息,这是为什么?我们前面在学习共享内存的时候,写入进程写入数据后,我们读取进程可以多次读取到数据,可是在消息队列中却只能读一次,原因是前面我们提到了在成功地读取了消息队列中的一条消息以后,队列中的这条消息将被删除。因此要想多次读取同样的消息,就得让发送进程多次发送。

以上便是linux进程通信之消息队列的简单介绍,希望得到指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值