消息队列就是一个消息的链表。

能够把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程能够向中依照一定的规则加入新消息。有读权限的进程则能够读走消息。

读走就没有了。消息队列是随内核持续的。 仅仅有内核重新启动或人工删除时。该消息才会被删除。

在系统范围内,消息队列与键值唯一相应。



关于消息队列使用的API

key_t ftok(const char *pathname, int proj_id);

#在IPC中,我们经经常使用一个 key_t 的值来创建或者打开 信号量,共享内存和消息队列。

这个 key_t 就是由ftok函数产生的。

pathname:指定的文件名称,该文件必须是存在并且能够訪问

proj_id:1~255之间的整数值。

对于ftok这个函数,个人是认为没有太大用处,第一,应用程序可能会在不同的主机上使用,(换了一个环境,文件有没有?)。第二点,假设在訪问同一共享内存的多个进程先后调用ftok这个时间段中, pathname指定的文件被删除且又一次创建,那么,每一个进程得到的 key_t 是不一样的,应用程序不会报错,可是数据共享的目的是达不到了。





int msgget(key_t key, int msgflg);

函数功能:打开、创建消息队列

key: 使用 IPC_PRIVATE 意味着即将创建新的消息队列。 官方的说法是用ftok产生一个key(鉴于上面关于ftok的介绍。个人比較认同的做法是自定义一个)使用。

msgflg:是一组标志。

IPC_CREAT:假设消息队列不存在,则创建一个消息队列

IPC_EXCL:仅仅有在消息队列不存在的时候,新的消息队列才建立。否则就产生错误。

对于这个參数通常是这样操作

#define PERM S_IRUSR | S_IWUSR | IPC_CREAT

然后把 PERM 当作msgflg。

成功返回消息队列的标识符。不成功返回-1,并设置errno。

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

函数功能:向消息队列发送一条消息

msqid: 为消息队列的id(msgget函数的返回值)

msgp:存放消息的结构体。一般例如以下定义:

struct msgbuf{

long m_type; // 消息类型,必须大于0

char m_text[n]; //消息的内容

}

msgsz:消息的长度(也就是msgbuf.m_text的长度)

msgflg:參考函数 msgrcv 。

成功返回0。否则返回-1。





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

函数功能:从消息队列中读取消息

msqid: 为消息队列的id(msgget函数的返回值)

msgp:存放消息的结构体。一般例如以下定义:

struct msgbuf{

long m_type; // 消息类型,必须大于0

char m_text[n]; //消息的内容

}

msgsz:消息的长度(也就是msgbuf.m_text的长度)

msgtyp:请求读取的消息类型,取值为

0 : 表示读取消息队列中的第一条消息

>0: 表示队列中类型为 msgtyp 的第一条消息被读取;假设 msgflg 设置成 MSG_EXCEPT ,则表示消息队列中除了类型是 msgtyp 的第一条消息将被读取。

msgflg:是一组标志。读消息标志msgflg能够为下面几个常值的或

IPC_NOWAIT 假设没有满足条件的消息,调用马上返回,此时,errno=ENOMSG(设置了就是不堵塞。否则就是堵塞)

MSG_EXCEPT 与msgtyp>0配合使用,返回队列中第一个类型不为msgtyp的消息

MSG_NOERROR 假设队列中满足条件的消息内容大于所请求的msgsz字节,则把该消息截断。截断部分将丢失。

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

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

函数功能:控制消息队列的使用

msqid:为消息队列的id (msget函数的返回值)

cmd:控制命令。

可取值例如以下:

IPC_STAT:得到消息队列的状态

IPC_SET:改变消息队列的状态

IPC_RMID:删除消息队列

buf:是一个结构体指针,当cmd为IPC_STAT的时候。取得的状态放入这个结构体中。假设要改变消息队列的状态,用这个结构体指定。

struct msqid_ds 结构体原型

struct msqid_ds {

    struct ipc_perm msg_perm;     /* 操作权限 */

    time_t          msg_stime;    /* 最后一个进程发送消息到消息队列的时间 */

    time_t          msg_rtime;    /* 最后一个进程读取消息队列中消息的时间 */

    time_t          msg_ctime;    /* 最后一个进程改动消息队列的时间 */

    unsigned long   __msg_cbytes; /*  当前在队列的字节数(标准) */

    msgqnum_t       msg_qnum;     /*  当前在队列的消息数量 */

    msglen_t        msg_qbytes;   /* 队列中同意的最大字节数 */

    pid_t           msg_lspid;    /* 最后一个发送消息的进程pid */

    pid_t           msg_lrpid;    /* 最后一个接收消息的进程pid */

};

成功返回0,否则返回-1。





演示样例程序

my_head.h

#ifndef MY_HEAD_H_INCLUDED
#define MY_HEAD_H_INCLUDED /*
包括经常使用头文件。编写測试代码用
*/ #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <errno.h> #endif // MY_HEAD_H_INCLUDED



msg.h

#include "my_head.h"

#define PERM    S_IRUSR | S_IWUSR | IPC_CREAT

struct msgbuf{
long m_type;
char m_text[128];
}; int open_msg_queue(key_t keyval); int send_msg_to_queue(int msqid, struct msgbuf buf, size_t msgsz); int recv_msg_from_queue(int msqid, struct msgbuf *buf, size_t msgsz); int delete_msg_queue(int msqid);

msg.c

#include "msg.h"

int open_msg_queue(key_t keyval){
int qid=msgget(keyval,PERM);
if(qid == -1)
fprintf(stderr,"%s %s %d\n",strerror(errno),__FILE__,__LINE__); return qid;
} int send_msg_to_queue(int msqid, struct msgbuf buf, size_t msgsz){
if(msgsnd(msqid,&buf,msgsz,0) == -1){
fprintf(stderr,"%s %s %d\n",strerror(errno),__FILE__,__LINE__);
return -1;
} return 0;
} int recv_msg_from_queue(int msqid, struct msgbuf *buf, size_t msgsz){
if(msgrcv(msqid,buf,msgsz,0,0) == -1){
fprintf(stderr,"%s %s %d\n",strerror(errno),__FILE__,__LINE__);
return -1;
}
return 0;
} int delete_msg_queue(int msqid){
if(msgctl(msqid,IPC_RMID,NULL) == -1){
fprintf(stderr,"%s %s %d\n",strerror(errno),__FILE__,__LINE__);
return -1;
}
return 0;
}

msg_send.c

#include "msg.h"

int main(){
struct msgbuf msg_buf; int msqid = open_msg_queue((key_t)1234); while(1){
printf("Enter: ");
fgets(msg_buf.m_text,sizeof(msg_buf.m_text),stdin); send_msg_to_queue(msqid,msg_buf,sizeof(msg_buf.m_text)); if(strncmp(msg_buf.m_text,"quit",4) == 0)
break;
} return 0;
}

msg_recv.c

#include "msg.h"

int main(){
struct msgbuf msg_buf; int msqid = open_msg_queue((key_t)1234); while(1){ recv_msg_from_queue(msqid,&msg_buf,sizeof(msg_buf.m_text)); printf("recv: %s",msg_buf.m_text); if(strncmp(msg_buf.m_text,"quit",4) == 0)
break;
} delete_msg_queue(msqid); return 0;
}



linux 进程间通信之 消息队列的更多相关文章

  1. [转]Linux进程间通信——使用消息队列

    点击此处阅读原文 另收藏作者ljianhui的专栏初学Linux 下面来说说如何使用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linu ...

  2. Linux进程间通信——使用消息队列

    下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信——使用命名管道   一.什么是消息队列 消息队列提 ...

  3. 练习--LINUX进程间通信之消息队列MSG

    https://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 继续坚持,或许不能深刻理解,但至少要保证有印象. ~~~~~~~~~~~~~~ 消息队 ...

  4. Linux进程间通信(消息队列/信号量+共享内存)

    写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...

  5. Linux进程间通信之消息队列

    本文依据以下思路展开,首先从宏观上阐述消息队列的机制,然后以具体代码为例进一步阐述该机制,最后试着畅想一下该通信机制潜在的应用. 消息队列是在两个不相关进程间传递数据的一种简单.高效方式,她独立于发送 ...

  6. Linux进程间通信(二) - 消息队列

    消息队列 消息队列是Linux IPC中很常用的一种通信方式,它通常用来在不同进程间发送特定格式的消息数据. 消息队列和之前讨论过的管道和FIFO有很大的区别,主要有以下两点(管道请查阅我的另一篇文章 ...

  7. linux下的进程间通信之消息队列

    概念: 进程彼此之间可以通过IPC消息进行通信.进程产生的每条消息都被发送到一个IPC消息队列中,这条消息一直存放在队列中,直到另一个进程将其读走为止. 优点:可以通过发送消息来几乎完全避免命名管道的 ...

  8. 进程间通信--POSIX消息队列

    相关函数: mqd_t mq_open(const char *name, int oflag); mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, si ...

  9. linux 进程间消息队列通讯

    转自:http://blog.csdn.net/lifan5/article/details/7588529 http://www.cnblogs.com/kunhu/p/3608589.html 前 ...

随机推荐

  1. 力扣题目汇总(反转字符串中的单词,EXCEL表列序号,旋置矩阵)

    反转字符串中的单词 III 1.题目描述 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序. 示例 1: 输入: "Let's take LeetCode ...

  2. RESTful API批量操作的实现

    要解决的问题 RESTful API对于批量操作存在一定的缺陷.例如资源的删除接口: DELETE /api/resourse/<id>/ 如果我们要删除100条数据怎么搞?难道要调用10 ...

  3. uboot的Makefile裁剪(针对飞思卡尔的mx6系列)

    VERSION = 2009PATCHLEVEL = 08SUBLEVEL =EXTRAVERSION =ifneq "$(SUBLEVEL)" ""U_BOO ...

  4. java 邮箱验证

    1.需要加入发送邮件的mail.jar: http://www.oracle.com/technetwork/java/javamail/index-138643.html 2.将字符串通过MD5进行 ...

  5. python常见陷阱

    copy to https://pythonguidecn.readthedocs.io/zh/latest/writing/gotchas.html 大多数情况下,Python的目标是成为一门简洁和 ...

  6. 【LeetCode】Broken Calculator(坏了的计算器)

    这道题是LeetCode里的第991道题. 题目描述: 在显示着数字的坏计算器上,我们可以执行以下两种操作: 双倍(Double):将显示屏上的数字乘 2: 递减(Decrement):将显示屏上的数 ...

  7. 多线程下,多次操作数据库报错,There is already an open DataReader associated with this Command which must be closed first.

    原文:https://www.cnblogs.com/sdusrz/p/4433108.html 执行SqlDataReader.Read之后,如果还想用另一个SqlCommand执行Insert或者 ...

  8. 自动化运维之shell引号和正则表达式(二)

    1 shell引号 1)反斜线\ 转译 echo * 显示当前目录中所有的文件列表 echo \* 显示*字符 换行 find / \ 换行输入多行命令 > -name "test.t ...

  9. 刷题总结——mayan游戏(NOIP2011提高组day2T3)

    题目: 题目背景 NOIP2011提高组 DAY1 试题. 题目描述 Mayan puzzle 是最近流行起来的一个游戏.游戏界面是一个 7 行 5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即 ...

  10. 刷题总结——瞭望塔(bzoj1038)

    题目: Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线 ...