Linux进程通信-消息队列

3 篇文章 0 订阅

系统调用函数

int msgget(key_t key, int msgflg);
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
int msgsnd(int msqid,struct msgbuf *msgp,size_t msgsz,int msgflg);
sszie_t msgrcv(int msqid,struct msgbuf *msgp,size_t msgsz,long msg_typ,int msgflg);

相关头文件:<sys/types.h>,   <sys/ipc.h>,    <sys/msg.h>, <stdio.h>      

1. int msgget ( key_t key, int msgflag )

功能:创建或获取标识为key的消息队列,并返回队列描述符。

返回:正确返回该消息队列的描述符msgid;错误返回-1。

参数:
key:消息队列标识符,为正整数。可由用户指定(适用于不同进程家族);也可使用IPC_PRIVATE由系统产生key值(适用于同一进程家族);
msgflag:标志或访问方式,由操作权限和控制命令进行或运算得到。
操作权限:三位数字对应 读/写/执行 0777=》111 111 111(2) 可读可写可执行
控制命令:IPC_CREAT(值0001000),若队列不存在则创建。

2. int msgctl( int msgid, int cmd, struct msqid_ds *buf )
功能:查询、设置消息队列的状态;撤消消息队列。

返回:函数调用成功返回0,不成功返回-1。

参数:
msgid:该消息队列id;

cmd:规定命令的类型:
IPC_STAT 查询消息队列状态,将消息队列的msqid_ds复制到buf;
IPC_SET 设置或修改消息队列状态,设置有效用户、组标识、操作允许权、字节数;
IPC_RMID 撤消描述符为msgid的消息队列;

buf:含有控制参数或查询结果的用户缓冲区的地址,可为0。

3. int msgsnd( int msgid, const void *msgp, size_t msgsz, int msgflag)
功能:将msgp->msgbuf中的消息复制到msgid消息队列中,将之挂到队尾,唤醒等待消息的进程。
参数:
msgid:执行msgget()返回的消息队列的描述符;
msgp:待发送的消息;
msgsz:由msgp指向的数据结构中消息长度,不包括类型type的长度;
msgflag:规定当消息队列满时应执行的动作,例如:若在flag中设置了IPC_NOWAIT,则当消息队列中的字节数超过最大值时(MSGMAX=8192),msgsnd立即返回,否则msgsnd睡眠。flag可置0。

struct msgbuf {
    long mtype;      //消息类型
    char mtext[1];   //消息数据,可以是其他结构
}

4. int msgrcv( int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflag)
功能:从msgid消息队列中接收一个消息:将消息复制到msgp->msgbuf中,并从队列中删除此消息,若消息未到则调用进程阻塞插入等待消息队列尾。
参数:
msgid—消息队列id;
msgp—存放接收消息的用户缓冲区的首地址;
msgsz —要接收字节数(一般为msgp中数据数组的大小),如果使用msgflag = MSG_NOERROR则小于实际的部分会被舍弃;反之会返回-1,errno=E2BIG,且消息依旧保存在消息队列中.
msgtype—接收消息类型:
=0–接收队列的第一个消息;
>0–接收类型为type的第一个消息,若指定MSG_EXCEPT则消息队列中第一个即使类型不符也会被读取;
<0—接收第一个类型小于或等于|type|的消息。
msgflag:若该队列无消息,内核应当做什么,可置0(阻塞)。

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

struct message {
    long type;
    char text[128];
} msg;

int isReady = 0;
int isExit = 0;

void setReady(int signal) {
    isReady = 1;
}

void setExit(int signal) {
    isExit = 1;
}

int main(int argc, char* argv[]) {
    key_t key = 113;        //随机值
    int status = 0;         
    pid_t pid = fork();     //创建子进程
    signal(12, setReady);   //自定义信号     

    if(pid == 0) {
        int msgqid = msgget(key, 0777 | IPC_CREAT);
        if(msgqid == -1) {
            printf("create message queue fail.\n");
            exit(1);
        }
        char childString[50] = "message from child.";
        msg.type = 1;
        strcpy(msg.text, childString);
        status = msgsnd(msgqid, &msg, sizeof(char) * strlen(childString), 0);
        if(status == -1) {
            printf("send message fail.\n");
            exit(1);
        }
        kill(getppid(), 12);    //通知父进程可以读消息队列
        while(isReady == 0) {   //等待父进程通知
            usleep(10);
        }   
        status = msgrcv(msgqid, &msg, sizeof(char) * 128, getpid(), 0);
        if(status == -1) {
            printf("receive message fail.\n");
            exit(1);
        }
        printf("child: receive message from parent: %s\n", msg.text);
        msgctl(msgqid, IPC_RMID, 0);
    } else if(pid > 0) {
        while(isReady == 0) {       //等待子进程通知
            usleep(10);
        }
        int msgqid = msgget(key, 0777 | IPC_CREAT);
        if(msgqid == -1) {
            printf("create message queue fail.\n");
            exit(1);
        }
        char parentString[50] = "message from parent.";

        status = msgrcv(msgqid, &msg, sizeof(char) * 128, 1, 0);
        if(status == -1) {
            printf("receive message fail...\n");
            exit(1);
        }
        printf("parent: receive message from child: %s\n", msg.text);
        msg.type = pid;
        strcpy(msg.text, parentString);
        status = msgsnd(msgqid, &msg, sizeof(parentString), 0);
        if(status == -1) {
            printf("send message fail.\n");
            exit(1);
        }
        kill(pid, 12);      //通知子进程可以读消息队列
    } else {
        printf("create child process fail.\n");
        exit(1);
    }   
    return 0;
}

通过信号机制通知父子进程读取消息队列的数据
ipcs -q 查看系统中的消息队列,、
ipcrm -q msgqid 删除消息队列

运行结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值