Linux 进程间通信(system v 消息队列, 阻塞式)实例


消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点。作为早期unix通信机制之一的信号能够传送的信息量有限,后来虽然POSIX 1003.1b在信号的实时性方面作了拓广,使得信号在传递信息量方面有了相当程度的改进,但是信号这种通信方式更像"即时"的通信方式,它要求接受信号的进程在某个时间范围内对信号做出反应,因此该信号最多在接受信号进程的生命周期内才有意义,信号所传递的信息是接近于随进程持续的概念(process-persistent);管道及有名管道及有名管道则是典型的随进程持续IPC,并且,只能传送无格式的字节流无疑会给应用程序开发带来不便,另外,它的缓冲区大小也受到限制。

/*
 *
 *       Filename:  producer.c
 *
 *    Description:  生产者进程
 *
 *        Version:  1.0
 *        Created:  09/30/2011 04:52:23 PM
 *       Revision:  none
 *       Compiler:  gcc(g++)
 *
 *         Author:  |Zhenghe Zhang|, |zhenghe.zhang@gmail.com|
 *        Company:  |Shenzhen XXX Technology Co., Ltd.|
 *
 */

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

#define BUFFER      10 //定义buf大小

struct msgtype {
    long mtype;
    char buf1[BUFFER + 1];
    char buf2[BUFFER + 1];
    long size;
};

int main()
{
    key_t msgkey;

    /*消息队列*/
    int msgid;
    struct msgtype msg;

    msgkey = ftok("/home/zhang/shmipcx", 10001);
    if(msgkey == -1)
    {
        perror("ftok");
        exit(1);
    }

    /*得到消息队列标识符或创建一个消息队列对象并返回消息队列标识符*/
    msgid = msgget(msgkey, IPC_CREAT | 0666);
    if(msgid == -1)
    {
        perror("msgget");
        exit(1);
    }

    int i = 0;
    while(i < 10)
    {
        memset(msg.buf1, 0, BUFFER + 1);
        memset(msg.buf2, 0, BUFFER + 1);

        sprintf(msg.buf1, "buf1_0x%x", i);      
        sprintf(msg.buf2, "buf2_0x%x", i + 'a');
      
        msg.mtype = 1001;
        msg.size  = i;

        printf("msg.mtype = %ld, msg.size = %ld\t", msg.mtype, msg.size);
        printf("msg.buf1 = %s, msg.buf2 = %s\n", msg.buf1, msg.buf2);

        /*将msgp消息写入到标识符为msqid的消息队列*/
        /*msgsz, 要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度*/
        /*msgflg 0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列*/
        /*msgflg IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回*/
        /*msgflg IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。*/       
        if(msgsnd(msgid, &msg, sizeof(struct msgtype) - sizeof(long), 0) == -1)
        {
            perror("msgsnd");
            exit(1);
        }

        i++;
        sleep(1);  
    }

    sleep(30); //等待消费者进程退出

    /*获取和设置消息队列的属性*/
    /*cmd IPC_STAT:获得msgid的消息队列头数据到buf中*/
    /*cmd IPC_RMID:删除消息队列*/
    if(msgctl(msgid, IPC_RMID, 0) == -1)
    {
        perror("msgctl");
        exit(1);
    }

    return 0;
}

 

/*
 *
 *       Filename:  consumer.c
 *
 *    Description:  消费者进程
 *
 *        Version:  1.0
 *        Created:  09/30/2011 04:52:23 PM
 *       Revision:  none
 *       Compiler:  gcc(g++)
 *
 *         Author:  |Zhenghe Zhang|, |zhenghe.zhang@gmail.com|
 *        Company:  |Shenzhen XXX Technology Co., Ltd.|
 *
 */

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

#define BUFFER      10 //定义buf大小

struct msgtype {
    long mtype;
    char buf1[BUFFER + 1];
    char buf2[BUFFER + 1];
    long size;
};

int main()
{
    key_t msgkey; 

    /*消息队列*/
    int msgid;
    struct msgtype msg;


    msgkey = ftok("/home/zhang/shmipcx", 10001);
    if(msgkey == -1)
    {
        perror("ftok");
        exit(1);
    }

    msgid = msgget(msgkey, IPC_EXCL | 0666);
    if(msgid == -1)
    {
        perror("msgget");
        exit(1);
    }
 
    int i = 0;

    while(i < 10) //运行一个consumenr,为 10 ,同时运行两个consumer进程,为 5 
    {
        memset(msg.buf1, 0, BUFFER + 1);
        memset(msg.buf2, 0, BUFFER + 1);
        msg.mtype = 1001;
        msg.size  = -1;
 
        /*从标识符为msqid的消息队列读取消息并存于msgp中,读取后把此消息从消息队列中删除*/
        /*msgp 存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同*/
        /*msgsz 要接收消息的大小,不含消息类型占用的4个字节*/
        /*msgtyp 0 接收第一个消息*/
        /*msgtyp <0 接收类型等于或者小于msgtyp绝对值的第一个消息*/
        /*msgtyp >0 接收类型等于msgtyp的第一个消息*/
        /*msgflg 0 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待*/
        /*msgflg IPC_NOWAIT 如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG*/
        /*msgflg IPC_EXCEPT 与msgtype配合使用返回队列中第一个类型不为msgtype的消息*/
        /*msgflg IPC_NOERROR 如果队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃*/
        if(msgrcv(msgid, &msg, sizeof(struct msgtype) - sizeof(long), msg.mtype, 0) == -1)
        {
            perror("msgrcv");
            exit(1);
        }

        printf("msg.mtype = %ld, msg.size = %ld\t", msg.mtype, msg.size);
        printf("msg.buf1 = %s, msg.buf2 = %s\n", msg.buf1, msg.buf2);

        i++;
        sleep(2);
    }

    return 0;
}

相关内容