1.概述

消息队列是内核地址空间中的内部链表,通过Linux内核在各个进程之间传递内容。消息顺序地发送到消息队列中,并以几种不同的方式从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识。内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是相对独立的。每个消息队列中的消息,又构成一个独立的链表。

2.消息缓冲区结构

消息缓冲结构(模板)如下所示:

struct msgbuf

{

long mtype; //消息类型

char mtext[1]; //消息数据,这个域并不一定要类型为char或长度为1,可根据实际情况设定。

};

自定义消息缓冲区例子:

struct msgbuf

{

long mtype;

char mtext[10];

long length;

};

3.结构msgid_ds

struct msgid_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

};

4.结构ipc_perm

struct ipc_perm

{

key_t key; /*函数msgget()使用的键值*/

uid_t uid; /*用户的UID*/

gid_t gid; /*用户的GID*/

uid_t cuid; /*建立者的UID*/

gid_t cgid; /*建立堵的GID*/

unsigned short mode; /*权限*/

unsigned short seq; /*序列号*/

};

5.键值构建ftok()函数

ftok()函数将路径名和项目的表示符转变为一个系统V的IPC键值,其原型如下:

#include<sys/types.h>

#include<sys/ipc.h>

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

注:也可以通过IPC_PRIVATE产生一个键值:

id = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR);

6.消息队列相关的函数原型

int msgget(key_t key, int msgflg); //消息队列创建

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);//发送消息

msgrcv(int msqid, void *msgq, size_t msgsz, long msgtyp, int msgflg);//接收消息

msgctl(int msgqid, int cmd, struct msqid_ds *buf);//消息队列控制

7.消息队列操作实例

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#include<string.h>

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

#define BUFSZ 512

struct message

{

long msg_type;

char msg_text[BUFSZ];

};

int main()

{

int qid;

key_t key;

int len;

struct message msg;

//产生键值

if((key= ftok(".", 'a')) == -1)

{

perror("ftok");

exit(1);

}

if((qid= msgget(key, IPC_CREAT | 0666)) == -1)

{

perror("msgget");

exit(1);

}

printf("openedqueue %d\n", qid);

puts("Pleaseenter the message to queue:");

if((fgets(msg.msg_text,BUFSZ, stdin)) == NULL)

{

puts("nomessage");

exit(1);

}

msg.msg_type=getpid();

len= strlen(msg.msg_text);

if(msgsnd(qid,&msg,len,0)) < 0)

{

perror("messageposted");

exit(1);

}

printf("messageis :%s\n", msg.msg_text);

if(msgctl(qid,IPC_RMID,NULL)) < 0)

{

perror("msgctl");

exit(1);

}

exit(0);

}

代码参考:

client 向server请求读取某个文件的内容

#include <sys/types.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stddef.h>     /* For definition of offsetof() */
#include <limits.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>#define SERVER_KEY 0x1aaaaaa1     /* Key for server's message queue */struct requestMsg {                /* Requests (client to server) */long mtype;                   /* unused */int clientId;                 /* ID of client's message queue */char pathname[PATH_MAX];      /* File to be returned */
}; #define REQ_MSG_SIZE (offsetof(struct requestMsg, pathname) - \offsetof(struct requestMsg, clientId) + PATH_MAX)#define RESP_MSG_SIZE 8192struct responseMsg {long mtype;char data[RESP_MSG_SIZE];
};/* Types for response messages sent from server to client */
#define RESP_MT_FAILURE 1       /* File couldn't be opened */
#define RESP_MT_DATA    2      /* Message contains file data */
#define RESP_MT_END     3     /* File data complete */

server:

#include "svmsg_file.h"static void               /* SIGCHLD handler */
grimReaper(int sig)
{int savedErrno;savedErrno = errno;  /* waitpid() might change 'errno' */while (waitpid(-1, NULL, WNOHANG) > 0)continue;errno = savedErrno;
}static void
serveRequest(const struct requestMsg *req)  /* Executed in child process: serve a single client */
{int fd;ssize_t numRead;struct responseMsg resp;fd = open(req->pathname, O_RDONLY);if (fd == -1) {                          /* Open failed: send error text */resp.mtype = RESP_MT_FAILURE;snprintf(resp.data, sizeof(resp.data), "%s", "Couldn't open");msgsnd(req->clientId, &resp, strlen(resp.data) + 1, 0);exit(EXIT_FAILURE);}resp.mtype = RESP_MT_DATA;while ((numRead = read(fd, resp.data, RESP_MSG_SIZE)) > 0)if (msgsnd(req->clientId, &resp, numRead, 0) == -1)break;/* Send a message of type RESP_MT_END to signify end-of-file */resp.mtype = RESP_MT_END;msgsnd(req->clientId, &resp, 0, 0);    /* Zero-length mtext */
}int
main(int argc, char *argv[])
{struct requestMsg req;pid_t pid;ssize_t msgLen;int serverId;struct sigaction sa;/* Create server message queue */serverId = msgget(SERVER_KEY, IPC_CREAT | IPC_EXCL |S_IRUSR | S_IWUSR | S_IWGRP);if (serverId == -1)perror("msgget");/* Establish SIGCHLD handler to reap terminated children */sigemptyset(&sa.sa_mask);sa.sa_flags = SA_RESTART;sa.sa_handler = grimReaper;if (sigaction(SIGCHLD, &sa, NULL) == -1)perror("sigaction error!");/* Read requests, handle each in a separate child process */for (;;) {msgLen = msgrcv(serverId, &req, REQ_MSG_SIZE, 0, 0);if (msgLen == -1) {if (errno == EINTR)continue;perror("msgrcv error");break;}pid = fork(); if (pid == -1) { perror("fork"); break; } if (pid == 0) { serveRequest(&req); _exit(EXIT_SUCCESS); } }/* If msgrcv() or fork() fails, remove server MQ and exit */if (msgctl(serverId, IPC_RMID, NULL) == -1)perror("msgctl");exit(EXIT_SUCCESS);}

client:

#include "svmsg_file.h"static int clientId;static void
removeQueue(void)
{if (msgctl(clientId, IPC_RMID, NULL) == -1)perror("msgctl");}int
main(int argc, char *argv[])
{struct requestMsg req;struct responseMsg resp;int serverId, numMsgs;ssize_t msgLen, totBytes;if (argc != 2 || strcmp(argv[1], "--help") == 0)perror("%s pathname\n", argv[0]);if (strlen(argv[1]) > sizeof(req.pathname) - 1)perror("pathname too long (max: %ld bytes)\n",(long) sizeof(req.pathname) - 1);/* Get server's queue identifier; create queue for response */serverId = msgget(SERVER_KEY, S_IWUSR);if (serverId == -1)perror("msgget - server message queue");clientId = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR | S_IWGRP);if (clientId == -1)perror("msgget - client message queue");if (atexit(removeQueue) != 0)perror("atexit");/* Send message asking for file named in argv[1] */req.mtype = 1;    /* Any type will do */req.clientId = clientId;strncpy(req.pathname, argv[1], sizeof(req.pathname) - 1);req.pathname[sizeof(req.pathname) - 1] = '\0';if (msgsnd(serverId, &req, REQ_MSG_SIZE, 0) == -1)perror("msgsnd");/* Get first response, which may be failure notification */msgLen = msgrcv(clientId, &resp, RESP_MSG_SIZE, 0, 0);if (msgLen == -1)perror("msgrcv");if (resp.mtype == RESP_MT_FAILURE) {printf("%s\n", resp.data);if (msgctl(clientId, IPC_RMID, NULL) == -1)perror("msgctl");exit(EXIT_FAILURE);}totBytes = msgLen;for (numMsgs = 1; resp.mtype == RESP_MT_DATA; numMsgs++) {msgLen = msgrcv(clientId, &resp, RESP_MSG_SIZE, 0, 0);if (msgLen == -1)perror("msgrcv");totBytes += msgLen;}printf("Received %ld bytes (%d messages)\n", (long) totBytes, numMsgs);exit(EXIT_SUCCESS);}

转载于:https://my.oschina.net/fuyajun1983cn/blog/263890

专题 12 IPC之消息队列相关推荐

  1. IPC之——消息队列

    消息队列作用: 可以用于两个没有联系的进程间通信,创建一个消息队列类似于打开了一个文件,两个不同的进程都可以进行操作 消息队列之函数介绍: 头文件:<sys/type.h> <sys ...

  2. linux 消息队列_Linux进程间通信第六讲 标准IPC之消息队列

    来源CSDN: CSDN-专业IT技术社区-登录​blog.csdn.net 一.概念和原理 消息队列是另一种标准IPC,当然也大概遵循大部分标准 消息队列,它是存放消息(数据)的队列,而队列是先进先 ...

  3. System V IPC之消息队列

    消息队列由消息队列id来唯一标识 消息队列就是一个消息的列表 用户可以在消息队列中添加消息 读取消息 消息队列可以按照类型来发送和接收消息       消息队列使用步骤 打开/创建消息队列 msgge ...

  4. Linux IPC 进程间通信——消息队列message

    消息队列是消息的连接表,存储在内核中.本实例主要实现消息队列方式进行进程间通信,接收端收到消息之后,立马转发给发送端:发送端发出消息之后,立马监听接收端回馈的消息,实现一个双向通信示例. 一.示例 发 ...

  5. Linux IPC POSIX 消息队列

    模型: #include<mqueue.h> #include <sys/stat.h> #include <fcntl.h> mq_open() //创建/获取消 ...

  6. System V IPC POSIX IPC(一):消息队列

    System V IPC & POSIX IPC(一):消息队列 消息队列允许进程之间以消息的形式交换数据,是一种常见的进程之间的通信机制. 1. 消息队列的创建 System V IPC: ...

  7. linux进程间通讯-消息队列

    文章目录 IPC对象 查看已经创建的IPC对象: 消息队列概述 消息队列的概念 消息队列的特点 在ubuntu 12.04中消息队列限制值如下 ftok函数 创建消息队列 -- msgget( ) 发 ...

  8. 智能家居DIY连载教程(2)——在实际项目中运用消息队列与邮箱

    前言 千呼万唤始出来,智能家居 DIY 教程连载第二篇终于登场了!本文将重点给大家介绍如何将消息队列与邮箱运用到实际项目中去.一起来看看吧~ DIY 回顾上期: 1.智能家居DIY连载教程(1)--如 ...

  9. Linux中的消息队列、共享内存,你确定都掌握了吗?

    消息队列(message queue) 消息队列是消息的链表,存放在内存中,由内核维护 消息队列的特点 1.消息队列中的消息是有类型的. 2.消息队列中的消息是有格式的. 3.消息队列可以实现消息的随 ...

最新文章

  1. Android WebView 和 javaScript的互相调用(三)
  2. 2009.09.01 博客近期改进公告!
  3. python编辑代码的页面_使用CodeMirror实现Python3在线编辑器的示例代码
  4. stylus在vue中的使用
  5. 快捷键关机电脑_技巧 | 如何知道电脑多久没关机?一个命令就行嘞!
  6. 使用libhybris库linux调用android库
  7. Delphi2010正式版的代码格式化及自动完成
  8. dnf时装预览怎么打开_dnf怎么查找各职业时装代码
  9. Sublime text 2 无需注册码的破解方法,只改2个字节
  10. MAC配置thinkPHP的心路历程(课设vue-tpadmin商城)
  11. 湖南师范大学2018年大学生程序设计竞赛新生赛 F 小名的回答
  12. 而立之年,第一篇博客,
  13. 流量卡之家:AI、无人机、物联网、自动驾驶 未来取决于5G
  14. stm32工程和算法分享(12)--精准闪烁灯[定时中断]
  15. 2022-2028全球与中国陆地和海洋测绘市场现状及未来发展趋势
  16. WebDAV之葫芦儿·派盘+墨阅
  17. PostFixサーバーインストール手順書
  18. 克拉克变换(Clarke Transformation)逆变换矩阵的求法
  19. 7. Lock 同步锁
  20. 应用程序0xc000007b无法正常启动,win10系统亲测有效

热门文章

  1. 最简单的nagios监控内存插件(shell)
  2. VMware使用方法
  3. Windows Server 2008安装Memcached笔记
  4. 重学前端-学习笔记-JavaScript对象
  5. 2018年台湾为陕西最大贸易伙伴
  6. java笔记 -- GregorianCalendar和DateFormateSymbols 类方法
  7. cordova contacts测试
  8. ArcGIS问题小记
  9. [转]parseUrl函数
  10. linux 密码记录文件 .netrc 简介