LINUX进程间的通信(IPC)--消息队列

一、概念

消息队列,是消息的链表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。

二、特点

*消息队列是面向记录的,其中的消息 具有特定的格式以及特定的优先级
*消息队列独立于发送和接收进程,进程 终止 时, 消息队列及其内容仍存在
*消息队列可以实现消息的随机查询,消息不 一定要先进先出的次序读取,也可以按消息的类型读取。

三、相关函数

1.int msgget(key_t key, int msgflg);

功能: 创建或打开消息队列,
参数:
key:         和消息队列关联的 key
msgflg :是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。 msgflg可以与IPC_CREAT做或操作 ,表示当key 所命名的消息队列不存在时创建一个消息队列,如果 key 所命名的消息队列存在时, IPC_CREAT 标志会被忽略,而只返回一个标识符。
返回值: 成功返回队列 ID ,失败则返回 ‐1
在以下两种情况下,msgget将创建一个新的消息队列:
1、如果没有与键值 key 相对应的消息队列,并且 flag 中包含了 IPC_CREAT 标志
2、key 参数为 IPC_PRIVATE
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>

int main()
{
        int msgID;
        msgID = msgget(IPC_PRIVATE,0755);
        if(msgID == -1)
        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }

        else
        {
                printf("消息队列创建成功\n");
                system("ipcs -q");//查看队列信息
        }
        return 0;
}
运行结果:

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

功能: 控制消息队列
参数:
msqid :消息队列的队列 ID
cmd
        1.IPC_STAT:把 msgid_ds 结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds 的值。
        2.IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为 msgid_ds 结构中给出的值IPC_RMID:删除消息队列
buf :是指向 msgid_ds 结构的指针,它指向消息队列模式和访问权限的结构
返回值:
成功: 0
失败: ‐1
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>

int main()
{
        int msgID,msgrnt;

        msgID = msgget(IPC_PRIVATE,0755);
        if(msgID == -1)
        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }

        else
        {
                printf("消息队列创建成功\n");
                system("ipcs -q");//查看队列信息
        }

        msgrnt = msgctl(msgID,IPC_RMID,NULL);
        if(msgrnt == -1)
        {
                printf("消息队列控制函数>删除失败\n");
                perror("msgctl");
                return -2;
        }
        else
        {
                printf("消息队列控制函数成功\n");
                system("ipcs -q");
        }
        return 0;
}
运行结果:

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

功能: 读取消息
参数:
msgid: 消息队列的 ID
msgp: 指向消息的指针,常用结构体 msgbuf 如下:
        struct msgbuf
        {
                long mtype; //消息类型
                char mtext[N]; //消息正文
        }
msgsz: 发送的消息正文你的字节数
msgflag:
                 IPC_NOWAIT:  消息没有发送完成函数也会立即返回
                 0:                   知道发送完成函数才返回
返回值:
成功: 0
失败: ‐1

4.ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

功能: 从一个消息队列中获取消息
 
参数:
msgid: 消息队列的 ID
msgp: 要接收消息的缓冲区
msgsz: 要接收的消息的字节数
msgtype:
        等于0:   接收消息队列中第一个消息
        大于0 :接收消息队列中第一个类型为 msgtyp 的消息
        小于0 :接收消息队列中类型值不大于 msgtyp 的绝对值且类型值又最小的消息。
flag:
        0:若无消息函数一直阻塞
        IPC_NOWAIT:若没有消息,进程会立即返回 ENOMSG
返回值:
成功:接收到的消息 i 长度
出错: ‐1
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
        long mtype; //消息类型
        char mtext[128]; //消息正文
};
int main()
{
        int msgID,msgrnt;
        struct msgbuf readBuf,writeBuf;
        int readRnt;

        msgID = msgget(IPC_PRIVATE,0755);
        if(msgID == -1)

        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }

        else
        {
                printf("消息队列创建成功,ID号为:%d\n",msgID);
        }

        //初始化结构体
        writeBuf.mtype = 100; //消息类型
        printf("请向%d号队列输入数据\n",msgID);
        memset(writeBuf.mtext,0,128);
        memset(readBuf.mtext,0,128);
        fgets(writeBuf.mtext,128,stdin);
        //向队列发送数据
        msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
        //从队列读取数据
        readRnt = msgrcv(msgID,(void *)&readBuf,128,100,0);

        printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
        return 0;
}

运行结果:
PS:消息队列的数据被读了之后,字节数会清除,但是队列中的内核节点依旧存在

5.ftok函数

key_t ftok( char * fname, int id )
功能: 系统建立 IPC 通讯(如消息队列、共享内存时)必须指定一个 ID 值。通常情况下,该 id 值通过 ftok 函数得到。
参数:
fname: 就时你指定的文件名 ( 该文件必须是存在而且可以访问的 )
id: 是子序号, 虽然为 int ,但是只有 8 个比特被使用 (0‐255)
返回值:
当成功执行的时候,一个 key_t 值将会被返回,否则 ‐1 被返回。
示例(半双工):
msg_read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
        long mtype; //消息类型
        char mtext[128]; //消息正文
};
int main()
{
        int msgID,msgrnt;
        struct msgbuf readBuf;
        int readRnt;
        key_t key;
        key = ftok("a.c",1);
        msgID = msgget(key,IPC_CREAT|0755);
        if(msgID == -1)

        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }

        else
        {
                while(1)
                {
                        memset(readBuf.mtext,0,128);
                        //从队列读取数据
                        readRnt = msgrcv(msgID,(void *)&readBuf,128,100,0);
                        printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
                }
        }
        return 0;
}

msg_write.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
        long mtype; //消息类型
        char mtext[128]; //消息正文
};
int main()
{
        int msgID,msgrnt;
        struct msgbuf writeBuf;
        key_t key;

        key = ftok("a.c",1);
        msgID = msgget(key,IPC_CREAT|0755);
        if(msgID == -1)

        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }

        else
        {
                printf("消息队列创建成功,ID号为:%d\n",msgID);
        }

        //初始化结构体
        writeBuf.mtype = 100; //消息类型
        while(1)
        {
                printf("请向%d号队列输入数据\n",msgID);
                memset(writeBuf.mtext,0,128);
                fgets(writeBuf.mtext,128,stdin);
                //向队列发送数据
                msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
        }
        return 0;
}

运行结果:
示例(全双工):
msg_client.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include<sys/types.h>
#include <sys/wait.h>

struct msgbuf
{
        long mtype; //消息类型
        char mtext[128]; //消息正文
};
int main()
{
        int msgID,msgrnt;
        struct msgbuf readBuf,writeBuf;
        int readRnt;
        pid_t pid;
        key_t key;
        key = ftok("a.c",1);
        msgID = msgget(key,IPC_CREAT|0755);
        if(msgID == -1)

        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }
        else
        {
                printf("消息队列创建成功,ID号为:%d\n",msgID);
        }

        pid = fork();
        if(pid == -1)
        {
                printf("fork fail!\n");
                perror("fork");
                return -2;
        }
        writeBuf.mtype = 200; //消息类型
        if(pid >0)//客户端父进程写200
        {
                while(1)
                {

                        printf("请向服务端%d号队列输入数据\n",msgID);
                        memset(writeBuf.mtext,0,128);
                        fgets(writeBuf.mtext,128,stdin);
                        //向队列发送数据
                        msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);

                }
        }

        if(pid == 0)//客户端子进程读100
        {
                while(1)
                {
                        memset(readBuf.mtext,0,128);
                        //从队列读取数据
                        readRnt = msgrcv(msgID,(void *)&readBuf,128,100,0);
                        printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
                }
        }
        return 0;
}

msg_service.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct msgbuf
{
        long mtype; //消息类型
        char mtext[128]; //消息正文
};
int main()
{
        int msgID,msgrnt;
        struct msgbuf readBuf,writeBuf;
        int readRnt;
        pid_t pid;
        key_t key;
        key = ftok("a.c",1);
        msgID = msgget(key,IPC_CREAT|0755);
        if(msgID == -1)

        {
                printf("消息队列创建不成功\n");
                perror("msgget");
                return -1;
        }
        else
        {
                printf("消息队列创建成功,ID号为:%d\n",msgID);
        }

        pid = fork();
        if(pid == -1)
        {
                printf("fork fail!\n");
                perror("fork");
                return -2;
        }
        writeBuf.mtype = 100; //消息类型

       if(pid == 0)//服务器子进程写100
        {
                while(1)
                {
                        //初始化结构体
                        printf("请向客户端%d号队列输入数据\n",msgID);
                        memset(writeBuf.mtext,0,128);
                        fgets(writeBuf.mtext,128,stdin);
                        msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
                }

        }

        if(pid > 0)//服务器父进程读200
        {
                while(1)
                {
                        memset(readBuf.mtext,0,128);
                        //从队列读取数据
                        readRnt = msgrcv(msgID,(void *)&readBuf,128,200,0);
                        printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
                }
        }
        return 0;
}
                                              

运行结果:
  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值