Linux进程间通信——使用System V 消息队列
消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。
在Linux中使用消息队列
Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信。
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。
ftok 函数
原型
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
调用成功返回一个key值,用于创建消息队列,如果失败,返回-1。
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。
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];
};
msgrcv 函数
是从一个消息队列接受消息
原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数
与msgsnd相同
返回值
成功返回实际放到接收缓冲区里去的字符个数,失败返回-1
常用命令
显示IPC资源
ipcs -q

手动删除IPC资源
ipcrm
消息最大长度上限(MSGMAX)
cat /proc/sys/kernel/msgmax
系统上消息队列的总数上限(MSGMNI)
cat /proc/sys/kernel/msgmni
每个消息队列的总的字节数(MSGMNB)
cat /proc/sys/kernel/msgmnb

代码示例
定义一个 msgque.h 文件
#ifndef __MSGQUE__H__
#define __MSGQUE__H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <getopt.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <pthread.h>
#include <poll.h>
#include <sys/msg.h>
#define MAXLEN 1024
#define MSG_KEY_DIR "/tmp"
typedef struct
{
long Type;
char Content[MAXLEN];
}MsgInfo;
int CreateMessage(const char*pathname,int proj_id);
int GetMessage(const char*pathname,int proj_id);
int SendMessage(int msgid,const char* msg,int type);
int ReceiveMessage(int msgid,char* msg,int type);
int DestoryMessage(int msgid);
#ifndef MSG
#define MSG(fmt...) \
do {\
printf("{%s}-[%s]-%d: ", __FILE__,__FUNCTION__, __LINE__);\
printf(fmt);\
}while(0)
#endif
#ifdef __cplusplus
}
#endif
#endif
定义 msgque.c 文件
# include "msgque.h"
int CreateMessage(const char*pathname,int proj_id)
{
key_t key = ftok(pathname,proj_id);
int ret = 0;
if((ret=msgget(key,IPC_CREAT|0666))==-1)
{
perror("Message Create Error: \r\n");
return -1;
}
return ret;
}
int GetMessage(const char*pathname,int proj_id)
{
key_t key = ftok(pathname,proj_id);
int ret = 0;
if((ret=msgget(key,IPC_CREAT))==-1)
{
perror("Message Get Error: \r\n");
return -1;
}
return ret;
}
int SendMessage(int msgid,const char* msg,int type)
{
MsgInfo buf;
buf.Type = type;
strcpy(buf.Content,msg);
if(msgsnd(msgid,&buf,sizeof(buf.Content),0) == -1)
{
MSG("Msg Send Error\n");
DestoryMessage(msgid);
return -1;
}
return 0;
}
int ReceiveMessage(int msgid,char* msg,int type)
{
MsgInfo buf;
if(msgrcv(msgid,&buf,sizeof(buf.Content),type,0)==-1)
{
MSG("Msg Recv Error\n");
DestoryMessage(msgid);
return -1;
}
strcpy(msg,buf.Content);
return 0;
}
int DestoryMessage(int msgid)
{
if(msgctl(msgid,IPC_RMID,NULL) == -1)
{
MSG("Msg Destroy Error\n");
return -1;
}
return 0;
}
int MessageCommon(key_t key,int flag)
{
int ret = 0;
if((ret=msgget(key,flag))==-1)
{
perror("MessageCommon Error: ");
}
return ret;
}
定义send.c 文件
# include "./msgque/msgque.h"
int main()
{
int running = 1;
char buffer[MAXLEN];
MsgInfo data;
int masgid = CreateMessage(MSG_KEY_DIR,0x01);
while(running)
{
printf("Enter data : ");
fgets(buffer, MAXLEN, stdin);
SendMessage(masgid,buffer,1);
if(strncmp(buffer, "end", 3) == 0)
{
DestoryMessage(masgid);
running = 0;
}
usleep(100000);
}
return 0;
}
定义recv.c 文件
# include "./msgque/msgque.h"
int main()
{
int running = 1;
char buffer[MAXLEN];
int masgid = GetMessage(MSG_KEY_DIR,0x01);
while(running)
{
ReceiveMessage(masgid,buffer,1);
printf("You wrote: %s\n",buffer);
if(strncmp(buffer, "end", 3) == 0)
{
running = 0;
}
usleep(100000);
}
exit(EXIT_SUCCESS);
}
测试结果:

Linux进程间通信——使用System V 消息队列的更多相关文章
- Linux进程通信之System V消息队列
System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...
- 进程间通信 System V 消息队列
1.msgget (key_t ket,int flag) ; //创建一个新的消息队列或者访问一个已存在的消息队列 2.msgsnd(int msid, const void *ptr ,size_ ...
- linux c编程:System V消息队列一
消息队列可以认为是一个消息链表,System V 消息队列使用消息队列标识符标识.具有足 够特权的任何进程都可以往一个队列放置一个消息,具有足够特权的任何进程都可以从一个给定队列读出一个消息.在某个进 ...
- linux网络编程之system v消息队列(二)
今天继续学习system v消息队列,主要是学习两个函数的使用,开始进入正题: 下面则开始用代码来使用一下该发送函数: 在运行之前,先查看一下1234消息队列是否已经创建: 用上次编写的查看消息队列状 ...
- 第6章 System V消息队列
6.1 概述 System V消息队列在内核中是list存放的,头结点中有2个指针msg_first 和msg_last.其中每个节点包含:下个节点地址的指针.类型.长度.数据等. 6.2 函数 6. ...
- 利用System V消息队列实现回射客户/服务器
一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并 ...
- UNIX环境高级编程——system V消息队列
unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的. 消息队列(也叫报文队列)客服了这些缺点: 消息队列就是一个消息的链表. 可以把消 ...
- 第二十五章 system v消息队列(一)
IPC对象的持续性 随进程持续 :一直存在直到打开的最后一个进程结束.(如pipe和FIFO) 随内核持续 :一直存在直到内核自举(内核自举就是把主引导记录加载到内存,并跳转执行这段内存)或显示删除( ...
- Linux进程间通信(System V) --- 消息队列
消息队列 IPC 原理 消息队列是消息的链式队列,如下图为消息队列的模型.整个消息队列有两种类型的数据结构. 1.msqid_ds 消息队列数据结构:描述整个消息队列的属性,主要包括整个消息队列的权限 ...
随机推荐
- 支付宝soa框架发展思路(转载)
大家好,这里是首届QCon Beijing的现场,现在坐在我的旁边是的支付宝的首席架构师程立.先给大家介绍一下,支付宝架构发展到今天,经历哪些时期,都有哪些里程碑? 我回忆一下,支付宝系统架构发展大概 ...
- code1068 乌龟棋
暴力显然不行,所以考虑dp 记f[i][j][k][l]为使用i张1,j张2,k张3,l张4所得到的最大分数. 对于每个f[i][j][k][l],都可以由i-1张1,j张2,k张3,l张4所得到, ...
- 熟悉相关电路,控制I/O口,且配置相关参数,LED,光敏,74LS164数码管
1.掌握zigbee无线模块的基本工作电路. 2.上面芯片跟仿真器连接需要5根线,电源.地.复位.P2_1.P2_2. 输出的配置:a.首先要让相应IO口处于普通IO口模式,非片上外设的模式:b.让普 ...
- 使用UrlRewriteFilter对url进行更替
一般来说,使用struts之后url的访问实际上访问的是action的地址,为了不让该地址暴露给别人,可以采用UrlRewriteFilter来对url进行重写. 首先,在web.xml里面配置: & ...
- HDU 6194 string string string (后缀数组)
题意:给定一个字符串,问你它有多少个子串恰好出现 k 次. 析:后缀数组,先把height 数组处理出来,然后每次取 k 个进行分析,假设取的是 i ~ i+k-1,那么就有重复的,一个是 i-1 ~ ...
- JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(11):XML和Annotation装配Bean的混合使用(@ImportResource)
一.XML和Annotation装配Bean如何合理使用 引入第三方资源包中类的时候,建议使用XML配置,而使用自己编写的Java类的时候,推荐使用Annotation注解配置Bean. 二.关于注解 ...
- Git SSH Key
一.设置Git的user name和email: $ git config --global user.name "hhl_vip" $ git config --global ...
- Linq的使用场景简介和认识
一:C#的一个分支Linq 二:学Linq需要有一些基础知识 1. var 隐式类型 2. 匿名类型/匿名方法 3. 自动属性 4. 委托/泛型的委托 5. lambda 6. 扩展方法 7. 对象初 ...
- [Erlang16]为什么要用MFA代替fun()–>end?
MFA:Module Function Arguments. 首先你要知道Module:Func(Args)和Func(Args)的区别在哪里? 如果对细节感兴趣,可以通过这里了解:http://ww ...
- Hadoop 文件命令
* 文件操作 * 查看目录文件 * $ hadoop dfs -ls /user/cl * * 创建文件目录 * $ hadoop dfs -mkdir /user/cl/temp * * 删除文件 ...