Linux消息队列

本文介绍了Linux下的消息队列,它是一种异步处理机制,常用于解耦和减少请求响应时间。消息队列操作包括创建、打开、添加消息、读取消息和控制。文章详细讲解了msgget、msgsnd、msgrcv和msgctl四个关键函数的使用,以及如何在Linux系统中查看和交互消息队列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消息队列:

·消息队列就是消息的链表,它允许一个或多个进程向它写消息,一个进程或多个进程从中读消息。具有一定的FIFO的特性,但是可实现消息的随即查询。这些消息存在于内核中,由“队列ID”来标识。

消息队列使用场景

·消息队列的主要特点是异步处理,目的是减少请求响应时间和解耦。通常使用在比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。

·由于使用了消息队列,只要保证消息格式不变,消息的发送方和接受方并不需要彼此联系,也不需要受对方的影响,即解耦和。

使用场景的话,举个例子:
假设用户在你的软件中注册,服务端收到用户的注册请求后,它会做这些操作:
  1. 校验用户名等信息,如果没问题会在数据库中添加一个用户记录
  2. 如果是用邮箱注册会给你发送一封注册成功的邮件,手机注册则会发送一条短信
  3. 分析用户的个人信息,以便将来向他推荐一些志同道合的人,或向那些人推荐他
  4. 发送给用户一个包含操作指南的系统通知
  5. 等等……
但是对于用户来说,注册功能实际只需要第一步,只要服务端将他的账户信息存到数据库中他便可以登录上去做他想做的事情了。至于其他的事情,非要在这一次请求中全部完成么?值得用户浪费时间等你处理这些对他来说无关紧要的事情么?所以实际当第一步做完后,服务端就可以把其他的操作放入对应的消息队列中然后马上返回用户结果,由消息队列异步的进行这些操作。

或者还有一种情况,同时有大量用户注册你的软件,再高并发情况下注册请求开始出现一些问题,例如邮件接口承受不住,或是分析信息时的大量计算使cpu满载,这将会出现虽然用户数据记录很快的添加到数据库中了,但是却卡在发邮件或分析信息时的情况,导致请求的响应时间大幅增长,甚至出现超时,这就有点不划算了。面对这种情况一般也是将这些操作放入消息队列(生产者消费者模型),消息队列慢慢的进行处理,同时可以很快的完成注册请求,不会影响用户使用其他功能。

所以在软件的正常功能开发中,并不需要去刻意的寻找消息队列的使用场景,而是当出现性能瓶颈时,去查看业务逻辑是否存在可以异步处理的耗时操作,如果存在的话便可以引入消息队列来解决。否则盲目的使用消息队列可能会增加维护和开发的成本却无法得到可观的性能提升,那就得不偿失了。


(来自知乎一个前辈的回答,

作者:ScienJus
链接:https://www.zhihu.com/question/34243607/answer/58314162)

Linux下消息队列

·消息队列的实现包括创建和打开队列、添加消息、读取消息和控制消息队列这四种操作。

linux下用四个函数实现:


·msgget:创建和打开队列,其消息数量受系统限制。

 所需头文件:#include <sys/types.h>

                      #include <sys/ipc.h>

                      #include <sys/shm.h>

 函数原型:int msgget(key_t key, int flag)

 函数传入值:Key:返回新的或已有队列ID,函数将它与已有的消息队
列对象的关键字进行比较来判断消息队列对象是否已经创建。 

                      Flag:消息队列的建立标志和存取权限

                      可以取以下值:

                       IPC_CREAT:创建新的消息队列

                       IPC_EXCL与IPC_CREAT:一同使用,表示如果要创建的消息队列已经存在,则返回错误。

                       IPC_NOWAIT:读写消息队列要求无法满足时,不阻塞。

 函数返回值:成功:消息队列ID

                       出错:-1


·msgsnd:添加消息,将消息添加到消息队列尾部

所需头文件:#include <sys/types.h>

                      #include <sys/ipc.h>

                      #include <sys/shm.h>

 函数原型:int msgsnd(int msqid,const void *prt,size_t size,int flag)

 函数传入值:

                      msqid:消息队列的id

                       prt:指向消息结构的指针,该消息结构msgbuf为:

                       struct msgbuf{

                       long mtype;//消息类型

                       char mtext[1];//消息正文}

                       size:消息的字节数,不要以null结尾

                       flag:IPC_NOWAIT若消息并没有立即发送而调用进程会立即返回

                                 0:msgsnd调用阻塞直到条件满足为止                      

 函数返回值:成功:0

                       出错:-1

·msgrcv:读取消息,从消息队列中取走消息

所需头文件:#include <sys/types.h>

                      #include <sys/ipc.h>

                      #include <sys/shm.h>

 函数原型:int msgsnd(int msqid, struct msgbuf *msgp, int size, long msgtype, int flag)

 函数传入值:

                      msqid:消息队列的id

                      msgp:消息缓冲区

                      size:消息的字节数,不要以null结尾

                      msgptype:0:接收队列中第一个消息

                                      大于0:接收消息队列中第一个类型为msgtyp的消息

                                      小于0:接收消息队列中第一个类型值不小于msgtyp绝对值且类型值又最小的消息

                      flag:MSG_NOERROR:若返回的消息比size字节多,则消息就会截短到size字节,且不通知消息发送                                                                  进程

                                IPC_NOWAIT:若消息并没有立即发送调用进程会立即返回

                                0:msgsnd调用阻塞直到条件满足为止                      

 函数返回值:成功:0

                       出错:-1

·msgctl:控制消息队列

所需头文件:#include <sys/types.h>

                      #include <sys/ipc.h>

                      #include <sys/shm.h>

 函数原型:int msgctl(int msqid, int cmd, nt size, long msgtype, int flag)

 函数传入值:

                      msqid:消息队列的id

                      cmd:IPC_STAT:读取消息队列的数据结构msqid_ds,并将其存在buf指定的地址中

                              IPC_SET: 设置消息队列的数据结构msqid_ds中的ipc_perm元素的值,这个值取自buf参数

                              IPC_RMID:从系统内核中移走消息队列

                     Buf:消息队列缓冲区

 函数返回值:成功:0

                       出错:-1


向消息队列添加消息:

/**
ipc_test_send.c
author:huangpingyi
date:2017/2/2
**/

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


#define MAX_TEXT 512 //缓冲区大小

struct my_msg_st {
     long int my_msg_type;
     char some_text[MAX_TEXT];
};

int main()
{

   int running = 1;
   struct my_msg_st some_data;
   int msgid;
   char buffer[BUFSIZ];

   printf("BUFSIZ=%d\n",BUFSIZ);
   msgid = msgget((key_t)1234,0666 |IPC_CREAT);
   if(msgid == -1){
   printf(stderr, "msgget failed with error: %d\n", errno);
   exit(1);
}
while (running){
    printf("Enter some text:");
    fgets(buffer,BUFSIZ,stdin);
    some_data.my_msg_type = 1;//初始化消息类型
    strcpy(some_data.some_text,buffer);//初始化消息内容
//添加消息到消息队列
    if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0)== -1){
       fprintf(stderr,"msgsnd faoled\n");
       exit(1);
}
if(strncmp(buffer, "end",3) == 0){
  running = 0;
}
}
return 0;
}

接收消息队列的消息:

/**
ipc_test_recv.c
author:huangpingyi
date:2017/2/2
**/

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


#define BUFSIZE 512 //缓冲区大小

struct my_msg_st {
     long int my_msg_type;
     char some_text[BUFSIZE];
};

int main()
{

   int running = 1;
   struct my_msg_st some_data;
   int msgid;
   long int msg_to_receive = 0;

   printf("BUFSIZ=%d\n",BUFSIZ);
   msgid = msgget((key_t)1234,0666 |IPC_CREAT);
   if(msgid == -1){
   fprintf(stderr, "msgget failed with error: %d\n", errno);
   exit(1);
}
while (running){
     //
     if(msgrcv(msgid,(void *)&some_data,BUFSIZE,msg_to_receive,0)==-1){
          fprintf(stderr,"msgrcv failed with error:%d\n",errno);
          exit(1);
      }
      printf("You  wrote : %s",some_data.some_text);
}
if(strncmp(some_data.some_text, "end",3) == 0){
  running = 0;
}
if(msgctl(msgid,IPC_RMID,0) == -1){
   fprintf(stderr,"msgct(IPC_RMID) failed\n");
   exit(1);
  }

return 0;
}


用ipcs  -q查看:

发送消息到消息队列:



接收消息:


发送和接收消息:



                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值