进程间通信IPC 主题一 之 消息队列
来源:互联网 发布:墨子号成功发射知乎 编辑:程序博客网 时间:2024/05/24 15:41
这是我们第一接触IPC主题系列先来看看
IPC简介:
XSI IPC 包括消息队列,信号量以及共享内存,他们都依托标识符和键来实现的,这就是像是管道靠文件描述符来实现一样。今天我们只了解消息队列。
IPC主题一:消息队列
一:什么是消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。消息队列与命名管道有一样的不足,就是每个消息队列的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。
我们用代码验证下消息队列的最大容量:
二:IPC对象数据结构
内核为每一个IPC对象维护了一个数据结构(/user/include/linux/ipc.h)
struct kern_ipc_perm{ //内核中记录消息队列的全局数据结构msg_ids能够访问到该结构; key_t key; //该键值则唯一对应一个消息队列 uid_t uid; gid_t gid; uid_t cuid; gid_t cgid; mode_t mode; unsigned long seq; }
消息队列,信号量和共享内存都有这样一个共同的数据结构;
三:消息队列结构
可以看到第一个条目就是IPC结构体,即使共有的,后面的都是消息队列的私有成员。
消息队列的特点:
(1) 存放的是有类型的数据块,并不像管道的那样针对字节流。
(2)生命周期随内核。
(3)所存在消息可以随机访问,不一定是先进先出。
(4)他是用链表实现的,所以可以实现一个或多个进程同时对读取或写入。
消息队列的创建
使用到的函数:
函数: key_t ftok(const char *filename, int proj_id);通过文件名和项目号获得System V IPC键值(用于创建消息队列、共享内存所用)proj_id:项目号,不为0即可返回:成功则返回键值,失败则返回-1----------函数: int msgget(key_t key, int msgflg);key:键值,当为IPC_PRIVATE时新建一块共享内存;msgflg:标志。IPC_CREAT:内存不存在则新建,否则打开;IPC_EXCL:只有在内存不存在时才创建,否则出错。返回:成功则返回标识符,出错返回-1----------函数: int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);向消息队列发送消息msgid:消息队列标识码,通过msgget获取msgp:指向一段暂时存储消息内容的指针 形态如下:struct msgstru{long mytype; //大于0char mtext[用户指定大小];}msgsz:消息内容的大小msgflg:处理方式;如为IPC_NOWAIT时表示空间不足时不会阻塞返回:成功则返回0,失败返回-1 ;当msgflg为0 时,msgsnd() 和 msgrcv() 都采用阻塞式等待。----------函数: int msgrcv(int msgid, void *msgp, size_t msgsz, long msgtype, int msgflg);从消息队列读取消息msgid:通过msgget获取msgp:指向一段暂时存储消息内容的指针 形态如下:struct msgstru{long mytype; //大于0char mtext[用户指定大小];}msgsz:消息内容的大小msgtype:指定接收的消息类型;若为0则队列第一条消息将被读取,而不管类型;若大于0则队列中同类型的消息将被读取,如在flg中设了MSG_RXCEPT位将读取指定类型的其他消息;若小于0读取绝对值小于type的消息。msgflg:处理方式;返回:成功返回收到消息长度,错误返回-1----------//设置消息队列属性函数: int msgctl(int msgid, int cmd, struct msgid_ds *buf);msgid:通过msgget获取cmd:控制命令,如下:IPC_STAT:获取消息队列状态(获取对应的msgid_ds),并保存在buf中指定的空间。IPC_SET:改变消息队列状态(设置属性存在buf中)IPC_RMID:删除(msgid标识的)消息队列buf:结构体指针,用于存放消息队列状态返回:成功返回与cmd相关的正数,错误返回-1
指令
ipcs -q 查看存在的消息队列
ipcrm -q +msgid 删除该消息队列
接下来我们用代码实现:
common.h
1 #ifndef _COMMON_H_ 2 #define _COMMON_H_ 3 #include <sys/types.h> 4 #include <sys/ipc.h> 5 #include <sys/wait.h> 6 #include <sys/msg.h> 7 #include <stdio.h> 8 #include <sys/stat.h> 9 #include <string.h> 10 #include <stdlib.h> 11 #define PATHNAME "." 12 #define PROJ_ID 0X6666 13 #define SERVER_TYPE 1 14 #define CLIENT_TYPE 2 15 #define SIZE 128 16 struct msgbuf 17 { 18 long mtype; 19 char mtext[SIZE]; 20 }; 21 22 int creatMsgQueue(); 23 int getMsgQueue(); 24 int sendMsg(int msgid, int type, const char* _info); 25 int recvMsg(int msgid, int type, char *out); 26 int destoryMsgQueue(int msgid); 27 28 #endif
common.c
1 #include "common.h" 2 3 int commMsgQueue(int flags) 4 { 5 key_t _k = ftok(PATHNAME, PROJ_ID); 6 if(_k < 0) 7 { 8 perror("ftok"); 9 return 1; 10 } 11 int msg_id = msgget(_k, flags); 12 if(msg_id < 0) 13 { 14 perror("msg"); 15 return 2; 16 } 17 return msg_id; 18 } 19 20 int creatMsgQueue() 21 { 22 return commMsgQueue(IPC_CREAT | IPC_EXCL | 0666); 23 } 24 25 int getMsgQueue() 26 { 27 return commMsgQueue(IPC_CREAT); 28 } 29 30 int destoryMsgQueue(int msgid) 31 { 32 if(msgctl(msgid, IPC_RMID, NULL) < 0) 33 { 34 perror("msgctl"); 35 return 1; 36 } 37 return 0; 38 } 39 40 int sendMsg(int msgid, int type, const char* _info) 41 { 1 #include "common.h" 2 int commMsgQueue(int flags) 3 { 4 key_t _k = ftok(PATHNAME, PROJ_ID); 5 if(_k < 0) 6 { 7 perror("ftok"); 8 return 1; 9 } 10 int msg_id = msgget(_k, flags); 11 if(msg_id < 0) 12 { 13 perror("msg"); 14 return 2; 15 } 16 return msg_id; 17 } 18 19 int creatMsgQueue() 20 { 21 return commMsgQueue(IPC_CREAT | IPC_EXCL | 0666); 22 } 23 24 int getMsgQueue() 25 { 26 return commMsgQueue(IPC_CREAT); 27 } 28 29 int destoryMsgQueue(int msgid) 30 { 31 if(msgctl(msgid, IPC_RMID, NULL) < 0) 32 { 33 perror("msgctl"); 34 return 1; 35 } 36 return 0; 37 }
server.c
1 #include "common.h" 2 3 int main() 4 { 5 char buf[SIZE]; 6 int msgid = creatMsgQueue(); 7 while(1) 8 { 9 if(recvMsg(msgid, CLIENT_TYPE, buf) < 0) 10 { 11 break; 12 } 13 printf("client say: %s\n", buf); 14 printf("please enter:"); 15 16 fflush(stdout); 17 ssize_t s = read(0, buf, sizeof(buf) - 1); 18 if(s > 0) 19 { 20 buf[s - 1] = 0; 21 if(sendMsg(msgid, SERVER_TYPE, buf) < 0) 22 { 23 break; 24 } 25 } 26 } 27 destoryMsgQueue(msgid); 28 return 0; 29 }
client.c
1 #include "common.h" 2 int main() 3 { 4 char buf[SIZE]; 5 int msgid = getMsgQueue(); 6 while(1) 7 { 8 printf("please enter$: "); 9 fflush(stdout); 10 11 ssize_t s = read(0, buf, sizeof(buf) - 1); 12 if(s > 0) 13 { 14 buf[s - 1] = 0; 15 if( sendMsg(msgid, CLIENT_TYPE, buf) < 0) 16 { 17 break; 18 } 19 } 20 if(recvMsg(msgid, SERVER_TYPE, buf) < 0) 21 { 22 break; 23 } 24 printf("server say: %s\n", buf); 25 } 26 return 0; 27 }
makefile:
下边是运行结果:
这样我们就通过消息队列实现了任意两个进程之间的双向通信!
- 进程间通信IPC 主题一 之 消息队列
- IPC进程间通信主题之消息队列
- 进程间通信(IPC)之消息队列
- IPC主题一之消息队列
- linux 进程间通信(IPC)一消息队列
- 进程通信 IPC 之消息队列
- 进程间通信---IPC对象 之 消息队列
- IPC主题一:消息队列
- 消息队列IPC---------用途:进程间通信
- 4、进程间通信-消息队列IPC
- Linux 进程间通信 (IPC) // 消息队列
- 进程间通信IPC-消息队列
- 进程间通信IPC-消息队列
- IPC进程间通信主题之信号量
- Linux进程IPC浅析[进程间通信SystemV消息队列]
- Linux — IPC进程通信之消息队列详解
- 笔记六:进程间的通信(IPC通信之消息队列)
- Linux IPC(进程间通信)摘要(信号灯,共享内存,消息队列,管道)(一)
- mysql 之: inner join , left join 和 right join 的区别
- 迪杰斯特拉堆优化
- 如何提高深度学习(和机器学习)的性能
- 二叉苹果树
- (一)IOC容器系列的设计与实现:BeanFactory和ApplicationContext
- 进程间通信IPC 主题一 之 消息队列
- 如何用C/C++程序获取博客的访问量和积分信息
- 欢迎使用CSDN-markdown编辑器
- Matplotlib 教程
- 队列
- ply格式点云在PCL中显示
- hdu 1050 Moving Tables(贪心经典,踩坑全集)
- Android7.0中文文档 --- CheckBox
- Hdu 2052 picture (感觉是对的姑且放一放)