专题 12 IPC之消息队列
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之消息队列相关推荐
- IPC之——消息队列
消息队列作用: 可以用于两个没有联系的进程间通信,创建一个消息队列类似于打开了一个文件,两个不同的进程都可以进行操作 消息队列之函数介绍: 头文件:<sys/type.h> <sys ...
- linux 消息队列_Linux进程间通信第六讲 标准IPC之消息队列
来源CSDN: CSDN-专业IT技术社区-登录blog.csdn.net 一.概念和原理 消息队列是另一种标准IPC,当然也大概遵循大部分标准 消息队列,它是存放消息(数据)的队列,而队列是先进先 ...
- System V IPC之消息队列
消息队列由消息队列id来唯一标识 消息队列就是一个消息的列表 用户可以在消息队列中添加消息 读取消息 消息队列可以按照类型来发送和接收消息 消息队列使用步骤 打开/创建消息队列 msgge ...
- Linux IPC 进程间通信——消息队列message
消息队列是消息的连接表,存储在内核中.本实例主要实现消息队列方式进行进程间通信,接收端收到消息之后,立马转发给发送端:发送端发出消息之后,立马监听接收端回馈的消息,实现一个双向通信示例. 一.示例 发 ...
- Linux IPC POSIX 消息队列
模型: #include<mqueue.h> #include <sys/stat.h> #include <fcntl.h> mq_open() //创建/获取消 ...
- System V IPC POSIX IPC(一):消息队列
System V IPC & POSIX IPC(一):消息队列 消息队列允许进程之间以消息的形式交换数据,是一种常见的进程之间的通信机制. 1. 消息队列的创建 System V IPC: ...
- linux进程间通讯-消息队列
文章目录 IPC对象 查看已经创建的IPC对象: 消息队列概述 消息队列的概念 消息队列的特点 在ubuntu 12.04中消息队列限制值如下 ftok函数 创建消息队列 -- msgget( ) 发 ...
- 智能家居DIY连载教程(2)——在实际项目中运用消息队列与邮箱
前言 千呼万唤始出来,智能家居 DIY 教程连载第二篇终于登场了!本文将重点给大家介绍如何将消息队列与邮箱运用到实际项目中去.一起来看看吧~ DIY 回顾上期: 1.智能家居DIY连载教程(1)--如 ...
- Linux中的消息队列、共享内存,你确定都掌握了吗?
消息队列(message queue) 消息队列是消息的链表,存放在内存中,由内核维护 消息队列的特点 1.消息队列中的消息是有类型的. 2.消息队列中的消息是有格式的. 3.消息队列可以实现消息的随 ...
最新文章
- Android WebView 和 javaScript的互相调用(三)
- 2009.09.01 博客近期改进公告!
- python编辑代码的页面_使用CodeMirror实现Python3在线编辑器的示例代码
- stylus在vue中的使用
- 快捷键关机电脑_技巧 | 如何知道电脑多久没关机?一个命令就行嘞!
- 使用libhybris库linux调用android库
- Delphi2010正式版的代码格式化及自动完成
- dnf时装预览怎么打开_dnf怎么查找各职业时装代码
- Sublime text 2 无需注册码的破解方法,只改2个字节
- MAC配置thinkPHP的心路历程(课设vue-tpadmin商城)
- 湖南师范大学2018年大学生程序设计竞赛新生赛 F 小名的回答
- 而立之年,第一篇博客,
- 流量卡之家:AI、无人机、物联网、自动驾驶 未来取决于5G
- stm32工程和算法分享(12)--精准闪烁灯[定时中断]
- 2022-2028全球与中国陆地和海洋测绘市场现状及未来发展趋势
- WebDAV之葫芦儿·派盘+墨阅
- PostFixサーバーインストール手順書
- 克拉克变换(Clarke Transformation)逆变换矩阵的求法
- 7. Lock 同步锁
- 应用程序0xc000007b无法正常启动,win10系统亲测有效