Linux进程通信之消息队列的双向通信
来源:互联网 发布:算法工程师有哪些证书 编辑:程序博客网 时间:2024/06/05 05:02
上一篇博客我写了进程间通信基于管道的通信,但是管道的通信无疑有很大的缺点,最显著的就是只能单向通信,例如:server向client发消息,client无法回复;第二个就是只能在有血缘关系的进程间进行通信,虽然命名管道解决了第二点,但是第一点还是一个很大的问题。开个玩笑:微信如果只能单向通信的话,你还会用吗?我估计发个消息能难受死你。
所以,这就是接下来几种进程间通信的产生条件。消息队列、信号量、共享内存都是基于system v 标准的进程间通信,均可产生双向通信的效果,并且并不局限于进程的关系,即:两个毫无关系的进程,只要均可以访问一块内核上的公共资源,就可以进行这三种基于system v的进程间通信。它是由操作系统IPC专门设定的一个接口,是一个进程向另一个进程发送数据块的方法,看过我上一篇博客的,我应该说过:管道是基于数据流的通信,所以这也是管道和基于system v的三种通信方式之间的差别。
消息队列也相当于一个资源,每个都有自己的编号,下面这个函数就是获得msgid的函数:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);
其中msgflg表示生成消息队列的方式和权限,一般使用的话,有三个常用参数,IPC_CREAT、IPC_EXCL、umask,IPC_CREAT单独使用时代表如果没有此消息队列,那就生成一个,如果当前的消息队列存在,那就打开它;IPC_EXCL单独使用没有任何意义,至少目前没有;二者同时使用表示如果没有此消息队列,则生成一个,如果有,那就出错并返回。而umask表示创建的当前的消息队列的权限,采用8进制表示。
解释一下,key值标识一个唯一的消息队列, 可以由系统指定产生,也可以由用户自己指定一个。在key的地方传IPCPRIVATE时表示系统指定key值。自定义生成key时,需要调用ftok函数。
#include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id);
pathname表示当前文件的名称或路径,proj_id可以忽略直接设为0。
则执行完msgget函数后,返回一个msgid。
首先我们要知道一点,因为之前说过消息队列是按数据块进行通信的,所以每个发送货接收的消息数据都在一个个的块里,每个块由一个结构体表示:
struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ };
发送函数:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgp表示这个结构体的地址,msgsz表示块中数据字段的长度,msgflg也忽略直接设为0;应注意,因为msgsnd函数中没有传入数据的类型和具体字符串,这就要求我们在传入结构体的时候,将结构体里面的两个字段都设置好。
接收函数:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgp、msgsz、msgflg的表示不变,msgtyp表示需要显式的传入类型。
在使用完毕消息队列后,我们要销毁创建的消息队列,防止占用系统资源。有两种方法可以做到:
1、直接在终端键入命令
ipcs -q:显式当前系统中的所有消息队列;
ipcrm -q [msgpid]:跟上msgid表示删除对应msgid的消息队列。
2、调用msgctl函数,顾名思义,控制函数,传入对应的参数就可以终止一个消息队列:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);
cmd处传入IPC_RMID就表示删除对应的消息队列,后面的参数可以先不管,直接传入NULL即可。
实现消队列的代码:
//comm.h#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <string.h>#define TEXT_SIZE 1024#define SERVER_TYPE 1#define CLIENT_TYPE 10struct msgbuf{ long mtype; /* type of message */ char mtext[TEXT_SIZE]; /* message text */};struct msgbuf msg;int creatmsgid();int getmsgid();int msgsend(int msgid,long types,const char* buffer);int msgreceive(int msgid,long types,char* buffer);int destroymsg(int msgid);
//comm.c#include "comm.h"static key_t getkey(){ return ftok("comm.h",0);//获得一个key}int creatmsgid(){ int msgid=msgget(getkey(),0666|IPC_CREAT|IPC_EXCL);//创建消息队列 if(msgid<0) { perror("masgget"); return -1; } return msgid;}int getmsgid(){ return msgget(getkey(),0666|IPC_CREAT);//注意msgget的参数}int msgsend(int msgid,long types,const char* buffer){ strcpy(msg.mtext,buffer);//先将结构体的两个字段赋值 msg.mtype=types; int ret=msgsnd(msgid,(void*)&msg,TEXT_SIZE,0); if(ret<0) { perror("msgsnd"); return -3; } return 0;}int msgreceive(int msgid,long types,char* buffer){ msg.mtype=types; ssize_t size=msgrcv(msgid,(void*)&msg,TEXT_SIZE,msg.mtype,0); if(size=0) { perror("msgrcv"); return -4; } printf("%s\n",msg.mtext); return size;}int destroymsg(int msgid){ int ret = msgctl(msgid,IPC_RMID,NULL); if(ret<0) { perror("msgctl"); return -2; } printf("message destroy done...\n"); return 0;}
//server.c#include "comm.h"int main(){ int running = 1; int msgid=creatmsgid(); char buff[1024]; int i=0; while(running) { printf("server enter# "); fflush(stdout); ssize_t s=read(0,buff,1024);//从键盘接收数据 buff[s-1]=0; msgsend(msgid,SERVER_TYPE,buff); printf("client say:"); fflush(stdout); msgreceive(msgid,CLIENT_TYPE,buff); } destroymsg(msgid); return 0;}
client.c#include "comm.h"int main(){ int msgid = getmsgid(); int running = 1; char buff[1024]; int i=0; while(1) { printf("server say:"); fflush(stdout); msgreceive(msgid,SERVER_TYPE,buff); printf("client enter#:"); fflush(stdout); ssize_t s=read(0,buff,1024); buff[s-1]=0; msgsend(msgid,CLIENT_TYPE,buff); } return 0;}
实现结果:
因为是阻塞方式实现的消息队列,所以只能等待发送或接收的操作完成后,再完成另外一个。
所以图片的最后在client say#的时候我就放弃发送了,因为server还没有发送,处在阻塞状态,不可能发送。
较大的图片传不上来,所以这个帧数较小。
- Linux进程通信之消息队列的双向通信
- Linux--进程通信之消息队列的双向通信
- Linux 进程间通信——消息队列实现双向通信
- linux进程间通信之消息队列
- linux进程间通信之消息队列
- linux进程间通信之消息队列
- Linux进程间通信之消息队列
- Linux进程通信之消息队列
- linux 进程间通信之消息队列
- linux进程间通信之消息队列
- linux进程间通信之消息队列
- Linux下进程通信之消息队列
- Linux进程通信之POSIX消息队列
- Linux进程通信之POSIX消息队列
- linux进程通信之消息队列
- Linux进程通信之POSIX消息队列
- linux进程间通信之消息队列
- linux进程间通信之消息队列
- qduoj 153 cfenglv的一道简单签到题 (二分+分解因子)
- 工厂模式
- 解决移动端可恨的滚动穿透问题
- c语言上机考试(二)
- Android ListView控件
- Linux进程通信之消息队列的双向通信
- keras的基本用法(五)——图像predict
- MySQl操作整理01
- 常用查找算法
- QT编译链接问题之一
- css之BFC总结
- Error:Execution failed for task ':app:mergeDebugResources'. > Some file crunching failed, see logs f
- SpringBoard相关api记录
- 【python 可视化】python利用matplotlib库绘制饼图案例