【IPC通信--消息队列】

消息队列(也叫做报文队列)是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。
IPC消息队列资源的限制
IPC消息队列的缺省数为16
每个消息的缺省最大值8192字节
队列中全部信息的缺省大小为16384字节

消息队列的概念和原理

消息队列是一种进程间通信(IPC)的机制,它允许不同进程之间通过消息进行交互。消息队列由内核负责管理,可以按顺序发送消息包(消息类型和消息内容),也可以全双工工作,即同时接收和发送消息。消息队列可以不按消息的顺序接收消息,因此具有一定的灵活性。

消息队列的应用场景

1.进程间通信:消息队列可以用于实现不同进程之间的通信,例如,一个进程需要向另一个进程发送数据或者通知,可以使用消息队列来实现。

2.异步处理:当一个进程需要异步处理某些任务时,可以使用消息队列来实现。例如,一个进程需要等待某个事件发生,它可以通过消息队列发送一个消息,通知另一个进程该事件已经发生。

3.任务分发:在分布式系统中,消息队列可以用于任务分发。例如,一个进程需要将某个任务分发给其他进程,它可以通过消息队列发送任务信息,其他进程收到消息后,可以按照任务要求进行处理。

4.日志记录:消息队列可以用于记录系统日志,当一个进程需要记录日志时,它可以将日志信息发送到消息队列,另一个进程可以实时接收并保存这些日志信息。

消息队列的优缺点

1.优点: 

   - 消息队列允许不同进程之间进行异步通信,提高了系统的并发性能。 

   - 消息队列具有一定的可靠性,即使接收进程没有及时处理消息,消息队列仍然可以保存消息。 

   - 消息队列可以实现进程间的解耦,降低了进程之间的依赖关系。

2.缺点: 

   - 消息队列的通信效率较低,因为消息需要经过内核的复制和传输。 

   - 消息队列的实现较为复杂,需要涉及到进程间通信、内存管理等方面的知识。

消息队列模型

操作消息队列

1打开或创建消息队列.
2读写操作:消息读写操作非常简单,对开发人员来说,每个消息都类似如下的数据结构:

struct msgbuf{
    long mtype;
    char mtext[1];
};
mtype 成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型; mtext 是消息内容,当然长度不一定为 1 。对于 发送消息来说,首先预置一个 msgbuf 缓冲区并写入消息类型和内容,调用相应的发送函数即可;对读取消息来说,首先分配这样一个 msgbuf 缓冲区,然后把消息读入该缓冲区即

3获得或设置消息队列属性

消息队列 API 共有四个,使用时需要包括几个头文件:
#include <sys/ types.h >
#include <sys/ ipc.h >
#include <sys/ msg.h >

消息队列的基本操作msgget()

功能
创建 一个新消息队列或 打开 一个存在的队列
函数原型
int msgget ( key_t key , int flag );
参数说明
key :待创建 / 打开队列的键值,如果 key 值为 IPC_PRIVATE 则创建一个新的消息队列。
flag :创建 / 打开方式
IPC_CREAT :如果存在与当前 key 值相同的消息队列,则返回该消息队列 id 。如果不存在,则创建一个新的消息队列。
IPC_EXCL :如果存在与当前 key 值相同的消息队列,则返回失败。
返回值
成功返回消息队列 描述符 ,否则返回 -1

ftok函数

ftok 原型:

      key_t   ftok( char * fname,       int id )

参数:

     fname指定的文件名(该文件必须是存在而且可以访问的)id是子序号,虽然为int,但是只有8个比特被使用(0-255)

返回值:

当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。

在一般的 UNIX 实现中,是将文件的索引节点号取出,前面加上子序号得到 key_t 的返回值。如指定文件的索引节点号为 65538 ,换算成 16 进制为 0x010002 ,而你指定的 ID 值为 38 ,换算成 16 进制为 0x26 ,则最后的 key_t 返回值为 0x26010002

消息队列的基本操作msgrcv()

函数 原型
ssize_t msgrcv (int msqid , struct msgbuf * msgp , size_t size , long type , int flag );
功能
该系统调用从 msqid 代表的消息队列中读取一个消息,并把消息存储在 msgp 指向的 msgbuf 结构中。
参数说明

msqid:消息队列描述字,描述从哪个消息队列读取消息

msgp:消息存储位置

size消息内容的长度(mtext[])

type:请求读取的消息类型

根据 type 的不同分成三种情况处理
type=0 :接收该队列的第一个消息,并将它返回给调用者
type>0 :接收类型 type 的第一个消息
type<0 :接收小于等于 type 绝对值的最低类型的第一个消息

消息队列的基本操作msgrcv()工作流程

flag:规定队列无消息时内核应做的操作

IPC_NOWAIT :如果现在没有消息,调用进程立即返回,同时返回 -1
IPC_EXCEPT type>0 时使用,返回第一个类型不为 type 的消息
IPC_NOERROR :如果队列中满足条件的消息内容大于所请求的 size 字节,则把该消息截断,截断部分将丢失。如果没有设置 IPC_NOERROR ,而消息又太长,则出错返回 E2BIG ,此时消息仍留在队列中。
调用返回:

成功返回读出消息的实际字节数,否则返回-1

注意:

取消息的时候并不一定按照先进先出的次序取消息,可以按照消息的类型字段取消息。

消息队列的基本操作msgsnd()

函数原型
int msgsnd (int msqid , struct msgbuf * msgp , size_t msgsize , int flag );
功能
msqid 代表的消息队列发送一个消息,即将发送的消息存储在 msgp 指向的 msgbuf 结构中,消息的大小由 msgze 指定。
参数说明
对发送消息来说,有意义 flag 标志为 IPC_NOWAIT ,指明在消息队列没有足够空间容纳要发送的消息时, msgsnd 是否等待。
造成 msgsnd () 等待的条件:
当前消息的大小与当前消息队列中的字节数之和 超过 了消息队列的 总容量
msgsnd () 解除阻塞的条件有三个:
消息 队列中有容纳该消息的空间;
msqid 代表的消息队列被删除;
调用 msgsnd ()的进程被信号中断
调用返回:成功返回 0 ,否则返回 -1

消息队列的基本操作msgctl()

函数原型
int msgctl (int msqid , int cmd , struct msqid_ds * buf );
功能
该系统调用对由 msqid 标识的消息队列执行 cmd 操作,共有三种 cmd 操作: IPC_STAT IPC_SET IPC_RMID
IPC_STAT :该命令用来获取消息队列信息,返回的信息存贮在 buf 指向 内存
IPC_SET :该命令用来设置消息队列的属性,要设置的属性存储在 buf 指向的 msqid_ds 结构 中;可设置属性包括: msg_perm.uid msg_perm.gid msg_perm.mode 以及 msg_qbytes
IPC_RMID :删除 msqid 标识的消息队列;

        调用返回:成功返回0,否则返回-1

消息队列使用示例——发送

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msg{
        long msg_types;
        char msg_buf[512];
};
int main()
{
        int qid;
        int pid;
        int len;
        struct msg pmsg;
        pmsg.msg_types = getpid();
        sprintf(pmsg.msg_buf, "hello!this is:%d\n",getpid());
        len = strlen(pmsg.msg_buf);
        //key_t key;
        //key = ftok(“usr/local/test”, 30);
        if((qid = msgget(0x66, IPC_CREAT | 0666))<0)
        {
                perror("msgget");
                exit(1);
        }
        if((msgsnd(qid, &pmsg, len, 0))<0)
        {
                perror("msgsnd");
                exit(1);
        }
        printf("successfully send a message to the queue:%d\n", qid);
	    system("ipcs  -q");
        return 0;
}

 消息队列使用示例——接收

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUFSIZE 4096
struct msg{
        long msg_types;
        char msg_buf[511];
};
int main(int argc, char* argv[])
{
        int qid, len;
        struct msg pmsg;
        qid = msgget(0x66,IPC_CREAT | 0666);
        //key_t key;
        //key = ftok(“usr/local/test”, 30);
        len = msgrcv(qid, &pmsg, BUFSIZE, 0, 0);
	    if(len > 0){
                pmsg.msg_buf[len] = '\0';
                printf("recving que id:%ld\n",qid);
                printf("message type:%d\n", pmsg.msg_types);
                printf("message length:%d\n",len);
                printf("message text:%s\n",pmsg.msg_buf);
        }else if(len == 0)
                printf("no message!");
        else{
                perror("msgrcv");
		      exit(0);
        }
        system("ipcs -q");
        exit(0);
}

相关推荐

  1. Linux进程间通信消息队列

    2024-01-08 10:20:03       22 阅读
  2. 多进程间通信学习之消息队列

    2024-01-08 10:20:03       42 阅读
  3. 【Linux 进程间通信(四)】System V 消息队列

    2024-01-08 10:20:03       28 阅读
  4. 消息 队列

    2024-01-08 10:20:03       15 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-08 10:20:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-08 10:20:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-08 10:20:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-08 10:20:03       20 阅读

热门阅读

  1. 用php实现日历输出

    2024-01-08 10:20:03       29 阅读
  2. React本地开发时,组件为啥会渲染两次

    2024-01-08 10:20:03       30 阅读
  3. go 切片长度与容量的区别

    2024-01-08 10:20:03       31 阅读
  4. 【前端规范】

    2024-01-08 10:20:03       35 阅读
  5. docker运行状态

    2024-01-08 10:20:03       29 阅读
  6. C++基础拾遗--看的不多只看一篇

    2024-01-08 10:20:03       34 阅读
  7. 【C语言】R7-5 奇偶排序

    2024-01-08 10:20:03       35 阅读
  8. Windows安装SonarQube9.9

    2024-01-08 10:20:03       39 阅读