weiqi7777

进击吧,linux(十八) 消息队列通讯

0
阅读(1581)

 

Linux进程和进程之间有多种通讯方式。Linux进程间通讯的主要方式有:

1、  无名管道

2、  有名管道

3、  信号

4、  消息队列

5、  共享内存

6、  信号量

7、  套接字

消息队列就是一个消息的链表。而一条消息可以看作是一个记录,具有特定的格式。进程可以向消息队列中按照一定的规则添加新消息,另一个进程可以从消息队列中读取消息,这样通过消息对了,就实现了进程间的通讯。

clip_image002

同样,对于消息队列,也是有若干函数。

9.1  创建或打开消息队列

9.1.1 函数名

    msgget

9.1.2 函数原型

    int msgget(key_t key, int msgflg)

9.1.3 函数功能

    打开或创建消息队列

9.1.4 函数所属头文件

    <sys/types.h> <sys/ipc.h> <sys/msg.h>

9.1.5 函数返回值

    成功: 消息对应标识符id

    失败: -1

9.1.6 函数参数

    key 消息队列关联的键值

    msgflg 打开标志

    -IPC_CREAT: 如果打开消息队列失败,则创建新的消息队列

9.2  写消息

9.2.1 函数名

    msgsnd

9.2.2 函数原型

    int msgsnd(int msqid, const void *msgp, size_t msgsz,int msgflg)

9.2.3 函数功能

    往消息队列里面发送消息

9.2.4 函数所属头文件

    <sys/types.h> <sys/ipc.h> <sys/msg.h>

9.2.5 函数返回值

    成功:0

    失败:-1

9.2.6 函数参数

    msqid: 消息队列的标识符id

    msgp: 指向要发送的消息指针

         clip_image003

                     mtext的大小由msgzz决定

    msgsz: 消息数据的大小

    msgflg: 标志

9.3  读消息

9.3.1 函数名

    msgrcv

9.3.2 函数原型

    ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg)

9.3.3 函数功能

    从消息队列获取消息

9.3.4 函数所属头文件

    <sys/types.h> <sys/ipc.h> <sys/msg.h>

9.3.5 函数返回值

    成功:实际接收到的消息的数据量

    失败:-1

9.3.6 函数参数

    msgid:消息队列的id

    msgp 消息指针

      clip_image003

    msgsz  希望取到消息的数据长度

    msgtyp:  消息类型

    -0 消息队列的第一条消息取出

    -大于0 取消息队列中第一条类型等于msgtyp的消息

    -小于0 取消息队列中类型不超过msgtyp的绝对值中最小的消息

    msgflg 标志

9.4  删除消息队列

9.4.1 函数名

    msgctl

9.4.2 函数原型

    int msgctl(int msgid, int cmd, struct msqid_ds *buf)

9.4.3 函数功能

    消息队列的操作

9.4.4 函数所属头文件

    <sys/types.h> <sys/ipc.h> <sys/msg.h>

9.4.5 函数返回值

    成功:0

    失败:-1

9.4.6 函数参数

    msgid: 消息队列id

    cmd:  命令

    -IPC_STAT: 将内核数据复制到buf

    -IPC_SET:  设置buf参数,并该buf数据复制到内核数据中

    -IPC_RMID: 删除消息队列

buf: 结构体指针

     clip_image005

 

      下面,就是写代码进行学习了。

       有两个进程AB,进程A创建消息队列,并向消息队列中写数据,进程B从消息队列中读取数据。

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
#include<string.h>
struct msgbuf{
    long mtype;
    char mtext[1024];
};
void main()
{
    key_t key;
    int msqid;
    char in[1024];
    struct msgbuf msg;
    int msg_type;
    /*获取键值*/
    key = ftok("/home",7); 
    /*创建消息队列*/
    msqid = msgget(key,IPC_CREAT);
    while(1)
    {
        printf("please input message type\n");     
        /*获取键盘输入*/
        scanf("%d",&msg_type);     
        printf("please input message content \n");
        scanf("%s",in);    
        msg.mtype = msg_type;
        strcpy(msg.mtext,in);      
        /*发送到消息队列*/
        msgsnd(msqid,&msg,sizeof(struct msgbuf),0);
        if(msg_type == 7777)
            break;
    }
    /*删除消息队列*/
    msgctl(msqid,IPC_RMID,0);
}       

进程A中定义了一个结构体,这个结构体就是消息队列中规定的消息的结构体。第一个成员是消息类型,规定要大于0。第二个是消息内容数组,用来保存消息的数据。

       首先是创建一个键值,然后创建消息队列和键值关联起来。然后就是一个无限循环,往消息队列中写入消息。如果一次消息发送的类型是7777,就退出循环,然后把消息队列删除。

       进程B

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
#include<string.h>
struct msgbuf{
    long mtype;
    char mtext[1024];
};
void main()
{
    key_t key;
    int msqid;
    struct msgbuf msg;
    key = ftok("/home",7);
    /*打开消息队列*/
    msqid = msgget(key, IPC_CREAT);
    while(1)
    {
        /*接收消息队列*/
        msgrcv(msqid,&msg,sizeof(struct msgbuf),0,0);
        /*打印消息队列*/
        printf("%d\n",msg.mtype);
        printf("%s\n",msg.mtext);
        if(msg.mtype == 7777)
            break;
    }
}

       进程B中也定义了一个和进程A中一样的结构体,功能是一样的。

       先创建键值,并打开与键值关联的消息队列,这样就可以和A进程进行消息通信了。然后就不断读取消息队列中的数据,打印出来,如果消息队列中的数据的类型是7777,就退出循环。

        这里接收消息用的是

                     msgrcv(msqid,&msg,sizeof(struct msgbuf),0,0);

        第三个参数是0,表示接收消息队列的第一个数据。

        程序运行:

        B进程在等待读取消息数据,因为A进程还没有发送消息,所以就被阻塞了。

clip_image007

A进程发送消息后,B进程就会收到该消息,然后将该消息打印出来。

clip_image009

当发送消息的类型是7777AB进程就结束运行了。

clip_image011

B进程的接收消息队列改为

msgrcv(msqid,&msg,sizeof(struct msgbuf),7,0);

表示只从消息队列中读取类型为7的消息。

运行程序的话,发送的消息类型不是7,就一直等待接收消息。

clip_image013

当发送消息类型为7,就接收消息。

clip_image015

 

B进程的接收消息队列改为

msgrcv(msqid,&msg,sizeof(struct msgbuf),-7,0);

表示只从消息队列中读取类型为1——7的消息。

运行程序的话,发送消息类型为15,超过7,所以B进程等待接收消息。

clip_image017

当发送消息的类型不超过7后,B进程接收消息。

clip_image019

以上,就是消息队列通信了,消息队列通信,对于接收,有3种方式,一种是接收消息队列的第一个,一个是接收消息队列中指定的类型消息,最后一个是接收消息队列中的指定的范围类型的消息。