Linux进程之间的通讯(IPC)--消息队列(MESSAGE)

二 消息队列(MESSAGE)

●消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表示。
●与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
●另外与管道不同的是,消息队列在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。

> 消息队列特点总结: 
>1)消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识.
>2)消息队列允许一个或多个进程向它写入与读取消息 (3)管道和消息队列的通信数据都是先进先出的原则。
>4)消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO更有优势。
> 消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺。
>5)目前主要有两种类型的消息队列:POSIX消息队列以及System V消息队列,System V消息队列目前被大量使用。System
> V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。

消息队列的使用
对于系统中的每个消息队列,内核维护一个定义在<sys/msg.h>头文件中的信息结构。

struct msqid_ds {
    struct ipc_perm msg_perm ; 
    struct msg*    msg_first ; //指向队列中的第一个消息
    struct msg*    msg_last ; //指向队列中的最后一个消息
    ……
} ;

msgget函数
调用的第一个函数通常是msgget,其功能是打开一个现存队列或创建一个新队列。

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

返回值是一个整数标识符,其他三个msg函数就用它来指代该队列。它是基于指定的key产生的,而key既可以是ftok的返回值,也可以是常值IPC_PRIVATE。
oflag是读写权限的组合(用于打开时)。它还可以是IPC_CREATE或IPC_CREATE | IPC_EXCL(用于创建时)。

msgsnd函数
使用msgsnd打开一个消息队列后,我们使用msgsnd往其上放置一个消息。

#include <sys/msg.h>
int  msgsnd (int msqid,  const void *ptr,  size_t length,  int flag) ;

其中msqid是由msgget返回的标识符。ptr是一个结构指针,该结构具有如下模板(我们需要按这个模板自己定义结构体)

struct mymesg {
    long  mtype ;     //消息类型(大于0)
    char  mtext[512] ;  //消息数据
} ;

//结构体的名字和其中变量名都由我们自己确定,我们只要按照这个模板定义即可。
消息数据mtext中,任何形式的数据都是允许的,无论是二进制数据还是文本,内核根本不解释消息数据的内容。(我们可以在消息的数据部分 再分割一部分 根据需要定义自己的通信协议)

参数length指定了待发送消息数据部分的长度。

参数flag的值可以指定为IPC_NOWAIT。这类似于文件IO的非阻塞IO标志。若消息队列已满,则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN

如果没有指定IPC_NOWAIT,则进程阻塞直到下述情况出现为止:①有空间可以容纳要发送的消息 ②从系统中删除了此队列(返回EIDRM“标识符被删除”)③捕捉到一个信号,并从信号处理程序返回(返回EINTR

msgrcv函数
使用msgrcv函数从某个消息队列中读出一个消息。

#include <sys/msg.h>
ssize_t  msgrcv (int msqid,  void* ptr,  size_t length,  long type,  int flag) ;

参数ptr指定所接收消息的存放位置。参数length指定了数据部分大小(只想要多长的数据)

参数type指定希望从队列中读出什么样的消息。

type == 0 返回队列中的第一个消息

type > 0 返回队列中消息类型为type的第一个消息

type < 0 返回队列中消息类型值小于或等于type绝对值的消息,如果这种消息有若干个。则取类型值最小的消息。

(如果一个消息队列由多个客户进程和一个服务器进程使用,那么type字段可以用来包含客户进程的进程ID)

参数flag可以指定为IPC_NOWAIT,使操作不阻塞。

msgctl函数
msgctl函数提供在一个消息队列上的各种控制操作。

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

参数cmd说明对由msqid指定的队列要执行的命令:

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

IPC_SET :按由buf指向结构中的值,设置与此队列相关结构中的字段。

IPC_RMID:从系统中删除该消息队列以及仍在该队列中的所有数据。
(这三条命令也可用于信号量和共享存储)

示例代码:
键值生消息队列接收端(msgGet.c)的代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

       //int msgget(key_t key, int msgflg);
        //int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
       //ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
struct msgbuf {
       long mtype;       /* message type, must be > 0 */
       char mtext[128];    /* message data */
};

int main()
{
        struct msgbuf readBuf;
        key_t key;
        //由ftok生成唯一键值
        key = ftok(".",'z');
        printf("key=%x\n",key);
		//打开/创建消息队列
        int msgId = msgget(key,IPC_CREAT|0777);
        if(msgId ==-1){
                printf("get que failuer\n");
        }

 //消息队列的数据读取  
        msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);
        printf("read from que:%s\n",readBuf.mtext);

        struct msgbuf sendBuf = {988,"thank you for reach"};
        msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);

        msgctl(msgId,IPC_RMID,NULL);

        return 0;
}

键值生消息队列发送端(msgSend.c)的代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
struct msgbuf {
        long mtype;       /* message type, must be > 0 */
        char mtext[128];    /* message data */
};

int main()
{
        //1.send
        struct msgbuf sendBuf = {888,"this is message from quen"};
        struct msgbuf readBuf;

        key_t key;					
        key = ftok(".",'z');		//键值生成队列,需要先生成key。
        printf("key=%x\n",key);

        int msgId = msgget(key,IPC_CREAT|0777);
        if(msgId ==-1){
                printf("get que failuer\n");
        }

        msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);

        msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);
        printf("return from get:%s\n",readBuf.mtext);

        msgctl(msgId,IPC_RMID,NULL);		//消除队列,第一个参数是队列的Id,第二个参数是命令,这里用消除的命令,第三个参数基本是写NULL。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值