[Linux]消息队列
我们知道进程间通信的方法有多种,主要有管道,消息队列,信号量,共享内存,socket等。之前介绍过管道,今天再介绍一个新的概念–消息队列。
消息队列:将一个进程到另一个进程之间发送数据块的方式。这些发送的数据块需要存在一个消息队列缓冲区中。这些数据块都是有一定的类型的,我们可以通过存放消息的数据块来避免命名管道与匿名管道所带来的同步与阻塞问题。与管道不同的是,消息队列是基于消息的,而管道是基于字节流的。同时,消息队列中存放的消息的数量是有限的。有最大长度(MSGMAX)和消息队列的总的字节数(MSGMNB)。也有系统规定的消息队列的总数(MSGMNI)。
内核为每个IPC对象维护了一个数据结构:struct ipc;
struct ipc_perm {
key_t __key; /* ftok所获取的唯一标识的key值*/
uid_t uid; /* 拥有者的有效uid*/
gid_t gid; /* 拥有者的有效gid */
uid_t cuid; /* 创建者的有效uid*/
gid_t cgid; /* 创建者的有效gid */
unsigned short mode; /* 权限 */
unsigned short __seq; /* 序列号*/
注:
消息队列,信号量,共享内存都有一个ipc数据结构。
在/usr/include/linux/msg.h下,有一个消息队列的数据结构:
由图可以看到ipc_perm就是刚刚说的几种通信方式所共有的数据结构。其他的一些就是消息队列结构体所私有的特性。还有其中的msg_first指针和msg_last指针分别指向消息队列的第一条消息和最后的消息。消息队列是用链表实现的。
同样,这幅图也是在msg.h中的。这里是消息缓冲区结构体和对于消息的一些信息。msgbuf结构体中的mtype是写的消息的长度大小,即mtext的size。数组mtext即是存放消息的数组。
消息队列的具体实现:
1.创建消息队列:
int msgget(key_t key,int msgflag);
key可以认为是端口号,由ftok生成一个唯一的key值。用来创建消息队列。
msgflag:是创建的消息队列的方式,有IPC_CREAT和IPC_EXCL。
(1)IPC_CREAT:单独使用时,如果已经存在已有的IPC资源,就直接返回已存在的IPC,如果不存在则创建一个新的IPC资源。
(2)IPC_CREAT|IPC_EXCL:同时使用时表示,不存在则创建一个,存在的话返回错误消息。
2.将消息发送到消息队列中
int msgsnd(int msgid,const void* msgp,size_t msgsz,int msgflg);
msgid:表示唯一确定的一个消息队列的id。
msgp: 表示存放数据的消息缓冲区
msgsz:消息文本的大小
msgflg:表示在队列没有数据的情况下进行的操作。一般设置为0,表示当队列空或满的时候,以阻塞式等待的方式进行处理。
3.从消息队列中取消息
ssize_t msgrgv(int msgid,const void* msgp,size_t msgsz,long msgtyp,int msgflg);
和上述往消息队列中写数据类似,这里取消息时,有msgtyp表示取哪种类型的消息,即消息队列中读取的消息形态。
4.设置消息队列的属性
int msgctl(int msgid,int cmd,struct msqid_ds *buf);
这里主要是对destroy进行操作,将cmd设置为IPC_RMID即可。
代码实现(server端与client端的通信):
//comm.h
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2struct msgbuf {long mtype;char mtext[1024];
};int createMsgqueue();
int getMsg();
int destroyMsg(int msgid);
int recvMsg(int msgid,long recvtype,char out[]);
int sendMsg(int msgid,long who,char* msg);#endif //_COMM_H//comm.c
#include"comm.h"int commMsgqueue(int flags)
{key_t _key = ftok(PATHNAME,PROJ_ID);if(_key < 0){perror("ftok");return -1;}int msgid = msgget(_key,flags);if(msgid < 0){perror("msgget");return -2;}return msgid;
}int createMsgqueue()
{return commMsgqueue(IPC_CREAT | IPC_EXCL|0666);
}
int getMsg()
{return commMsgqueue(IPC_CREAT);
}
int destroyMsg(int msgid)
{if(msgctl(msgid,IPC_RMID,NULL) < 0){perror("msgctl");return -1;}return 0;
}int recvMsg(int msgid,long recvtype,char out[])
{struct msgbuf buf;if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvtype,0) < 0){perror("msgrcv");return -1;}strcpy(out,buf.mtext);return 0;
}int sendMsg(int msgid,long who,char* msg)
{struct msgbuf buf;buf.mtype=who;strcpy(buf.mtext,msg);if(msgsnd(msgid,(void*)&buf,sizeof(buf.mtext),0) < 0){perror("msgsnd");return -1;}return 0;
}//server.c
#include"comm.h"
#include<stdio.h>int main()
{int msgid = createMsgqueue();char buf[1024];while(1){buf[0]=0;recvMsg(msgid,CLIENT_TYPE,buf);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;sendMsg(msgid,SERVER_TYPE,buf);printf("send done,wait recv...\n");}}destroyMsg(msgid);return 0;
}//client.c
#include"comm.h"
#include<stdio.h>int main()
{int msgid = createMsgqueue();char buf[1024];while(1){buf[0]=0;recvMsg(msgid,CLIENT_TYPE,buf);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;sendMsg(msgid,SERVER_TYPE,buf);printf("send done,wait recv...\n");}}destroyMsg(msgid);return 0;
}
[xiaoxu@bogon msgqueue]$ cat client.c
#include<stdio.h>
#include"comm.h"int main()
{int msgid = getMsg();char buf[1024];while(1){buf[0]=0;printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,CLIENT_TYPE,buf);printf("send done,wait recv...\n");}recvMsg(msgid,SERVER_TYPE,buf);printf("server# %s\n",buf);
}return 0;
}
//Makefile
.PHONY:all
all:client serverclient:client.c comm.cgcc -o $@ $^
server:server.c comm.cgcc -o $@ $^.PHONY:clean
clean:rm -f server client
[Linux]消息队列相关推荐
- linux消息队列非亲缘,linux进程
linux进程Tag内容描述: 1.linux消息队列进程通信 一.消息队列的基本概念消息队列(也叫做报文队列)是Unix系统V版本中3种进程间通信机制之一.另外两种是信号灯和共享内存.这些IPC机制 ...
- linux.调整收发队列,linux消息队列通信
程序目的:学习linux消息队列通信 所用主要函数:msgget(),msgsnd(),msgrcv(),msgctl() 首先介绍每个函数的用法: (1)msgget 使用格式: #include ...
- linux 消息队列 msgget/msgsnd/msgrecv
专栏内容:linux下并发编程 个人主页:我的主页 座右铭:天行健,君子以自强不息:地势坤,君子以厚德载物. 目录 前言 概述 原理 消息队列的大小 查看资源 接口 代码演示 结尾 前言 本专栏主要分 ...
- php 阻塞消息队列,linux 消息队列阻塞
php 使用socket告知Python,可以在socket上声明是及时推送还是延迟推送######哦?愿闻其详 那要是很多用户同时并发呢######system 调用外部程序是一种办法######@ ...
- PHP下操作Linux消息队列完成进程间通信的方法
2019独角兽企业重金招聘Python工程师标准>>> 来源:http://www.jb51.net/article/24353.htm 关于Linux系统进程通信的概念及实现可查看 ...
- linux 消息队列机制
现在我们来讨论第三种也是最后一种System V IPV工具:消息队列.在许多方面看来,消息队列类似于有名管道,但是却没有与打开与关闭管道的复杂关联.然而,使用消息队列并没有解决我们使用有名管道所遇到 ...
- linux消息队列的内核限制
[from:http://blog.csdn.net/cwj649956781/article/details/8804908] 消息队列: 1.每次msgrcv一个消息,1.那个消息会在内核中移除 ...
- linux消息队列总结
1.消息队列简介 实现linux进程通信的方式有5种: --信号(Singal) --管道(Pipe) --消息队列(Message) --信号量(Semaphore) 每种进程通信方式实现方式和功能 ...
- linux 消息队列_Linux消息队列
消息队列,Unix的通信机制之一,可以理解为是一个存放消息(数据)容器.将消息写入消息队列,然后再从消息队列中取消息,一般来说是先进先出的顺序.可以解决两个进程的读写速度不同(处理数据速度不同),系统 ...
最新文章
- C++ OpenCV形态学操作--开闭操作,形态学梯度,顶帽,黑帽
- 实战 Spring Cloud Gateway 之限流篇
- matlab jp2格式,JP2文件扩展名_JP2是什么格式_JP2文件怎么打开-文件百科
- 2021 年 6 月程序员工资统计,惨不忍睹。。。
- document.ready和window.onload的区别
- Zabbix实战-简易教程--订阅类
- nginx ---- nginx.conf核心配置文件
- random.choice与random.choices
- 物流管理系统(SSM+vue+shiro)【前后台】
- linux异步事件框架,基于Cortex-M系列CPU的异步事件驱动中间件
- 由于没有安装音量控制程序,WINDOWS无法在任务栏上显示音量控制,怎么解决?
- CSS Cascading Style Sheet 级联样式表1
- jasypt 配置文件加解密
- Datagrip连接mysql错误[08S01]解决办法
- 安卓Android手机直播推送同步录像功能设计与实现源码
- 自用的一些平时记录. 时不时更新
- MySQL InnoDB配置统计信息
- 辛巴学院-Unity-剑英的c#提高篇(一)主循环
- 总结vicky写的增删div
- 一分钟教你如何识别图片文字
热门文章
- loss function
- KingPaper初探ThinkPHP3.1.2之扩展函数库和类库的使用(四)
- Linux 引导管理器 grub2 使用简介
- 收集到的非常好的第三方控件
- mac mysql创建本地数据库_【mac】配置本地数据库
- minio 并发数_c#(asp.net)线程配置总结
- 远程教育英语和计算机没过怎么办,网络教育英语统考能考几次 没考过怎么办?...
- Mysql函数访问oracle,Oracle与MySql函数
- php在window磁盘管理,Windows Server 2008R2设置磁盘阵列
- apache gobblin mysql_gobblin简单使用