在上一篇博客里,我们学习了进程间通信的一种方式,那就是管道,今天我们继续学习另一种方式消息队列

消息队列

一. 什么是消息队列?

  消息队列是消息的链表,存放在内核中并由消息队列标识符表示。
  消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型。
  但是同管道类似,它有一个不足就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数(MSGMNB),系统上消息队列的总数上限(MSGMNI)。可以用cat /proc/sys/kernel/msgmax查看具体的数据。
  内核为每个IPC对象维护了一个数据结构struct ipc_perm,用于标识消息队列,让进程知道当前操作的是哪个消息队列。每一个msqid_ds表示一个消息队列,并通过msqid_ds.msg_first、msg_last维护一个先进先出的msg链表队列,当发送一个消息到该消息队列时,把发送的消息构造成一个msg的结构对象,并添加到msqid_ds.msg_first、msg_last维护的链表队列。在内核中的表示如下:


二. 特点:

  • 生命周期随内核,消息队列会一直存在,需要我们显示的调用接口删除或使用命令删除
  • 消息队列可以双向通信
  • 克服了管道只能承载无格式字节流的缺点

三. 消息队列函数

1.msgget

功能:创建和访问一个消息队列
原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflag);

参数
key:某个消息队列的名字,用ftok()产生
msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。
返回值:成功返回一个非负整数,即消息队列的标识码,失败返回-1

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

调用成功返回一个key值,用于创建消息队列,如果失败,返回-1

2.msgctl

功能:消息队列的控制函数
原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

参数
msqid:由msgget函数返回的消息队列标识码
cmd:有三个可选的值,在此我们使用IPC_RMID

  • IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
  • IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
  • IPC_RMID 删除消息队列

返回值
成功返回0,失败返回-1

3.msgsnd

功能:把一条消息添加到消息队列中
原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数
msgid:由msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgze:msgp指向的消息的长度(不包括消息类型的long int长整型)
msgflg:默认为0
返回值:成功返回0,失败返回-1

消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型

struct msgbuf
{long mtye;char mtext[1];
};

4.msgrcv

功能:是从一个消息队列接受消息
原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:与msgsnd相同
返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1


此外,我们还需要学习两个重要的命令
前面我们说过,消息队列需要手动删除IPC资源
ipcs:显示IPC资源
ipcrm:手动删除IPC资源


下面用代码模拟实现client与server之间的通信
comm.h

#ifndef _COMM_H_
#define _COMM_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>struct msgbuf
{long mtype;char mtext[1024];
};#define SERVER_TYPE 1
#define CLIENT_TYPE 2int createMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msg_id);
int sendMsgQueue(int msg_id, int who, char* msg);
int recvMsgQueue(int msg_id, int recvType, char out[]);#endif

comm.c

#include "comm.h"static int commMsgQueue(int flags)
{key_t key = ftok("/tmp", 0x6666);if(key < 0){perror("ftok");return -1;}int msg_id = msgget(key, flags);if(msg_id < 0){perror("msgget");}return msg_id;
}int createMsgQueue()
{return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}int getMsgQueue()
{return commMsgQueue(IPC_CREAT);
}int destoryMsgQueue(int msg_id)
{if(msgctl(msg_id, IPC_RMID, NULL) < 0){perror("msgctl");return -1;}return 0;
}int sendMsgQueue(int msg_id, int who, char* msg)
{struct msgbuf buf;buf.mtype = who;strcpy(buf.mtext, msg);if(msgsnd(msg_id, (void*)&buf, sizeof(buf.mtext), 0) < 0){perror("msgsnd");return -1;}return 0;
}int recvMsgQueue(int msg_id, int recvType, char out[])
{struct msgbuf buf;int size=sizeof(buf.mtext);if(msgrcv(msg_id, (void*)&buf, size, recvType, 0) < 0){perror("msgrcv");return -1;}strncpy(out, buf.mtext, size);out[size] = 0;return 0;
}

server.c

#include "comm.h"int main()
{int msgid = createMsgQueue();char buf[1024] = {0};while(1){recvMsgQueue(msgid, CLIENT_TYPE, buf);if(strcasecmp("quit", buf) == 0)break;printf("client# %s\n", buf);printf("Please enter# ");fflush(stdout);ssize_t s = read(0, buf, sizeof(buf));if(s>0){buf[s-1]=0;sendMsgQueue(msgid, SERVER_TYPE, buf);printf("send done, wait recv...\n");}}destoryMsgQueue(msgid);return 0;
}

client.c

#include "comm.h"int main()
{int msgid = getMsgQueue();char buf[1024] = {0};while(1){printf("Please Enter# ");fflush(stdout);ssize_t s = read(0, buf, sizeof(buf));if(s > 0){buf[s-1]=0;sendMsgQueue(msgid, CLIENT_TYPE, buf);if(strcasecmp("quit", buf) == 0)break;printf("send done, wait recv...\n");}recvMsgQueue(msgid, SERVER_TYPE, buf);printf("server# %s\n", buf);}return 0;
}


【Linux】进程间通信之消息队列相关推荐

  1. c语言系统编程八:Linux进程间通信之消息队列

    Linux进程间通信之消息队列 一 消息队列概述 二 消息队列的特点 三 消息队列的创建和使用 3.1 获取系统唯一的key值 3.2 创建消息队列 3.3 查看消息队列和删除消息队列的shell命令 ...

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

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

  3. Linux进程间通信(IPC)-------消息队列

    消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据) 下面来看消息队列的 创建,写入,读取等需要用到的函数 ...

  4. linux 进程uhxuhao,linux 进程间通信三 消息队列以及实例

    转自 http://blog.csdn.net/liang890319/article/details/8280934 代码来自:嵌入式Linux应用开发标准教程 消息可以理解为写信给某个人,这里在应 ...

  5. linux进程间通信:消息队列实现双端通信

    双端通信描述 利用消息队列针对发送接受消息的类型唯一性 进行多个客户端之间消息传递,而不需要server端进行消息转发. 同时消息队列的读阻塞和写阻塞特性(消息队列中已经写入数据,如果再不读出来,则无 ...

  6. linux 消息对lie_Linux进程间通信之消息队列总结

    一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d ...

  7. linux消息通信无法接收,进程间通信:消息队列有关问题:进程1接收不到进程2的消息...

    进程间通信:消息队列有关问题:进程1接收不到进程2的消息 进程间通信:消息队列有关问题:进程1接收不到进程2的消息 日期:2014-05-16 浏览次数:20365 次 进程间通信:消息队列问题:进程 ...

  8. 进程间通信之消息队列

    一.什么是消息队列 unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便.消息队列(也叫做报文队列)则克服了这些缺点. 消息队列就是一个消息 ...

  9. Linux系统中消息队列,共享内存、信号和线程的基本操作使用方法

    Linux系统中消息队列,共享内存.信号和线程高级操作 第十一章 消息队列 10.1消息队列定义 10.2 消息队列特点 10.3 key值 10.4 创建消息队列 10.4.1 发送消息 10.4. ...

  10. linux软中断和消息队列结合,传统UNIX进程间通信内核实现概要

    1概述 大型的应用系统,有两种方式可以建立: 1.通过一个孤立的.大型的.复杂的进程实现全部功能:如见日益复杂,规模庞大,该方法已不现实 2.通过若干相互联系的.小型的.相对简单的进程构成的组合来提供 ...

最新文章

  1. MySQL 行锁功过:怎么减少行锁对性能的影响
  2. mysql必知必会学习笔记(一)
  3. LeetCode 1103. 分糖果 II
  4. For循环(十分重要)
  5. IOS基础:ActionSheet(上拉菜单)的实现
  6. Tigase数据库结构(1)
  7. ffmpeg -视频旋转和高清转码示例
  8. Linux下Socket客户端服务器通信
  9. 贷款利息及公积金知识点
  10. [2005.04.28 13:36:04] 孤岛热浪的联想
  11. 日志平台查询异常,没有打印异常信息
  12. 用React加CSS3实现微信拆红包动画
  13. 西数打造面向数据中心的Gold产品组合
  14. 为不同分辨率的手机创建界面
  15. bzGhost 打造跨平台即时聊天软件之websocket
  16. Python数据分析:柱形图的绘制方法
  17. 使用 admin 管理后台
  18. QWebView到QWebEngineView
  19. 【CSAPP】家庭作业2.77~2.97
  20. css动画与渐变案例,使用动画和渐变做一个背景动态网页

热门文章

  1. 学计算机的逻辑学博士,逻辑学博士点
  2. python基础(八):进制转换及python中的进制转换方法
  3. Linux学习总结(1)——Linux命令大全完整版
  4. Securing Gateways with HTTPS(0.8)
  5. 免费的video解析接口
  6. 偶极子天线的优缺点_关于偶极子天线的若干问题。
  7. Pandownload 百度网盘光速下载 十分简单 一秒破解
  8. API网关之-协议转换原理
  9. 【每天一个 Linux 命令】ssh 命令
  10. React开发chrome插件系列教程之插件开发环境搭建