进程间通信-消息对列

原理说明:

消息队列是内核地址空间中的内部链表,通过linux内核在各个进程之间传递内容,消息顺序地发送到消息队列中,并且以几种不同的方式

从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识,内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是

相互独立的,每个消息队列中的消息又构成一个独立的链表.

 

消息队列中的数据结构

1、消息缓冲结构

向消息队列发送消息时,必须组成合理的数据结构。Linux系统定义了一个模版数据结构msgbuf:

#include<linux/msg.h>

struct msgbuf{

long type;

char mtext[1];

}

其中type表示消息的类型,以正数表示。mtext是该消息的数据,并不一定就是char 类型,任意类型都可以的。

2、msqid_ds内核数据结构。

struct msqid_ds{

   struct ipc_perm msg_perm;

   time_t msg_stime;

   time_t msg_rtime;

   time_t msg_ctime;

   unsigned long _msg_cbuyes;

    ..........

   };

 

Linux内核中,每个消息队列都维护一个结构体,此结构体保存着消息队列当前状态信息,该结构体在头文件linux/msg.h中定义。

3、ipc_perm内核数据结构

struct ipc_perm{

  key_t key;

  uid_t uid;

  gid_t gid;

  .......

};

结构体ipc_perm保存着消息队列的一些重要的信息,比如说消息队列关联的键值,消息队列的用户id组id等。它定义在头文件linux/ipc.h中

 

Linux的消息队列(queue)实质上是一个链表, 它有消息队列标识符(queue ID). msgget创建一个新队列或打开一个存在的队列; msgsnd向队列末端

添加一条新消息; msgrcv从队列中取消息, 取消息是不一定遵循先进先出的, 也可以按消息的类型字段取消息. 

 

 

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

  int msgget(key_t key, int msgflg);

 

参数key是一个键值,由ftok获得;msgflg参数是一些标志位。该调用返回与健值key相对应的消息队列描述字,如果没有消息队列与健值key相对应,

并且msgflg中包含了IPC_CREAT标志位或者key参数为IPC_PRIVATE,那么该调用将创建一个新的消息队列。

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);

该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中。

 msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz指定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读

取的消息类型,成功返回读出消息的实际字节数,否则返回-1。

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);

向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp指向的msgbuf结构中,消息的大小由msgze指定。

 对发送消息来说,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。成功返回0,否则

返回-1。

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

该系统调用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。

 

IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid结构中;

IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、

                msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。

IPC_RMID:删除msqid标识的消息队列;

 

 

 

read.c

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <stdio.h>

typedef struct msg_st
{
    long int msg_type;
    char text[BUFSIZ];
} MSG_ST ;

int main()
{
    int running = 1;
    int msgid = -1;
    MSG_ST data;
    long int msgtype = 2;
    
    msgid =  msgget((key_t)1234,0666 | IPC_CREAT);
    
    if(msgid == -1)
    {
        puts("msgget fail \n");
        exit(EXIT_FAILURE);
    }
    
    while(running)
    {
        if(msgrcv(msgid,(void *)&data,BUFSIZ,msgtype,0) == -1)
        {
            puts("msgrcv fail \n");
            exit(EXIT_FAILURE);
        }
        printf("rcv data type %d\n",data.msg_type);
        printf("rcv data text %s\n",data.text);
        
        if(strncmp(data.text,"end",3)==0)
            running = 0;
    }
    
    if(msgctl(msgid,IPC_RMID,0)==-1)
    {
        printf(stderr,"msgctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_FAILURE);

}

 

write.c

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
typedef struct msg_st
{
    long int msg_type;
    char text[MAX_TEXT];
}MSG_ST;

int main()
{
    int running = 1 ;
    struct msg_st data;
    char buffer[BUFSIZ];
    int msgid = -1;
    printf("bufsize size is %d\n",BUFSIZ);
    printf("MAX_TEXT is %d\n",MAX_TEXT);
    
    msgid = msgget((key_t)1234,0666 | IPC_CREAT);
    if(msgid == -1)
    {
        puts("msgget fail !\n");
        exit(EXIT_FAILURE);    
    }
    
    while(running)
    {
        puts("input data");
        fgets(buffer,BUFSIZ,stdin);
        data.msg_type = 2;
        strcpy(data.text,buffer);
        
        if(msgsnd(msgid,(void *)&data,MAX_TEXT,0) == -1)
        {
            puts("msgsnd fail !\n");
            exit(EXIT_FAILURE);            
        }
        
        if(strncmp(buffer,"end",3)==0)
            running = 0;
        sleep(1);
                
    }
    puts("exit success\n");
    exit(EXIT_FAILURE);
    


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值