进程间通信------------消息队列

为什么会有消息队列?

首先消息队列也是两个进程间进行数据传输的一个方式,除了这个作用外,还有一点就是当不同进程间传送消息时,由于进程进耦合度较高(一个进程的改变可能会影响到另一个进程)为了隔离两个进程,在两个进程之间抽出一块空间(消息队列),两个进程间传递的所有消息都必须通过消息队列。

理解消息队列

1、基本概念

消息队列就是一个存放消息的链表,对消息队列有写权限的进程就可以向消息队列中添加消息,对消息队列有读权限的进程就可以读走消息,写到了上限就不能写了,除非有人读走一些消息,读完了就没法再读,除非有人往里面写消息。
IPC对象数据结构:
这里写图片描述
消息队列结构:
这里写图片描述
这就是一整个消息队列:
这里写图片描述

2、消息队列的优缺点

1、可以实现异步通信
2、消息队列有大小限制。
3、实现简单,可移植性好。

用消息队列模拟实现客户端-服务器通信

服务器:
1、 服务器一定要先启动,在server.c中先将消息队列创建好,实时的接受客户端发来的消息(接受请求)
2、对客户端发送来的消息进行处理(此处是简易版,省略此步骤)
3、将结果返回给客户端,只有客户端退出服务器端才退出。(请求响应)
客户端:
1、从标准输入中获取数据
2、将数据发送到服务器端(发送请求)
3、接收服务器的响应。

写代码之前要介绍几个函数:

1、 msgget函数:用来创建和访问一个消息队列。
函数成功返回一个非负整数 即消息队列的标识码,失败返回-1;>

 int  msgget(key_t key,int msgflag);
 //key是消息队列的名字,msgflag是由九个权限标志构成,
 //用来指定按什么行为创建消息队列,指定消息队列的权限。

2、msgctl函数:消息队列的控制函数
成功返回0,失败返回-1

int msgctl(int msgid,int cmd,struct msgid_ds* buf);
//msgid是有msgget函数返回来的消息队列标识码。
//cmd是将要采取的动作(三个可能值)分别为:
//IPC_STAT:把msgid_ds结构体中的数据设置为消息队列的当前关联值
//IPC_SET:在进程有足够权限的前提下,把消息队列的当前关联值设置为msgid_ds数据结构中给出的值。
//IPC_RMID:删除消息队列。

msgsnd函数:把一条消息添加到消息队列中
成功返回0,失败返回-1;

int msgsnd(int msgid,const void* msgp,size_t msgsz,int msgflg);
//参数:msgid:消息队列标识码
//msgp:是一个指针,指向准备发送的消息。
//msgsz:msgp指向的消息长度(计算的长度不包含long int的保存消息类型的成员)
//msgflg:控制当前队列满或者到达系统上限即将发生的事情。为IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。

comm.h文件:

 2 #include<stdlib.h>
  3 #include<sys/msg.h>
  4 #include<sys/ipc.h>
  5 #include<sys/types.h>
  6 
  7 #define PATHNAME "."//当前路径
  8 #define PROJ_ID 0x6666//用于创建消息队列,构造ipc中的key

  9 #define request  1
 10 #define respond  2//用于说明发送消息队列和接收消息队列时是以请求还是响应的状态。
 11 
 12 struct msgbuf{
 13     long mtype;
 14     char mtext[1024];
 15 };//消息结构
 16 
 17 int createMsgQueue();
 18 int openMsgQueue();
 19 int destroyMsgQueue(int msgid);
 20 int sendMsgQueue(int msgid,int sendtype,char* msg,size_t size);
 21 int recvMsgQueue(int msgid,int recvtype,char output[]);

comm.c文件:

  2 #include<stdio.h>
  3 #include<sys/ipc.h>
  4 #include<sys/msg.h>
  5 #include<sys/types.h>
  6 #include<string.h>
  7 static int commMsgQueue(int flags){
  8     key_t key=ftok(PATHNAME,PROJ_ID);
  9     if(key<0){
 10         perror("ftok\n");
 11         return -1;
 12     }
 13     int msgid=msgget(key,IPC_CREAT|IPC_EXCL);
 14     if(msgid<0){
 15         perror("msgget\n");
 16         return -1;
 17     }
 18     return msgid;
 19 }
 20 int createMsgQueue(){
 21    return   commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
 22 }
 23 int openMsgQueue(){
 24     return commMsgQueue(IPC_CREAT);
 25 }
 26 int destroyMsgQueue(int msgid){
 27     if(msgctl(msgid,IPC_RMID,NULL)<0){
 28         perror("msgctl");
 29         return -1;
 30     }
 31     return 0;
 32 }
 33 int sendMsgQueue(int msgid,int sendtype,char* msg,size_t size){
 34     struct msgbuf buf;
 35     buf.mtype=sendtype;
 36     if(size>=sizeof(buf.mtext)/sizeof(buf.mtext[0])){
 37         printf("msg is too long\n");
 38         return -1;
 39     }
 40     strcpy(buf.mtext,msg);
 41     if(msgsnd(msgid,&buf,sizeof(buf.mtext)/sizeof(buf.mtext[0]),0)<0){
 42         perror("msgsnd\n");
 43     }
 44     return 0;
 45 }
 46 int recvMsgQueue(int msgid,int recvtype,char output[]){
 47     struct msgbuf buf;
 48     buf.mtype=recvtype;
 49     if(msgrcv(msgid,&buf,sizeof(buf.mtext),recvtype,0)<0){
 50         perror("msgrcv\n");
 51         return -1;
 52     }
 53     strcpy(output,buf.mtext);
 54     return 0;
 55 }

此处着重讲一下发送消息队列函数和接收消息队列函数
这里写图片描述

这里写图片描述

client.c文件:

  1 #include"comm.h"
  2 #include<string.h>
  3 int main(){
  4     int msgid=openMsgQueue();
  5     char buf[1024]={0};
  6     while(1){
  7     printf("please enter:");
  8     fflush(stdout);
  9     ssize_t read_size= read(0,buf,sizeof(buf)-1);
 10     if(read_size<0){
 11         perror("read\n");
 12         return -1;
 13     }else if(read_size>0){
 14       sendMsgQueue(msgid,request,buf,strlen(buf));
 15       printf("wait receive...\n");
 16     }
 17     else{
 18         printf("exit\n");
 19     }
 20     recvMsgQueue(msgid,respond,buf);
 21     printf("server say:%s\n",buf);
 22     }
 23     return 0;
 24 }

server.c文件:

 1 #include"comm.h"
  2 int main(){
  3     int msgid=createMsgQueue;
  4     char output[1024]={0};
  5     while(1){
  6         recvMsgQueue(msgid,request,output);
  7         printf("client say:%s\n",output);
  8         printf("================\n");
  9         fflush(stdout);
 10         ssize_t s=read(0,output,sizeof(output));
 11         if(s>0){
 12             sendMsgQueue(msgid,respond,output,strlen(output));
 13             printf("response has been made\n");
 14         }
 15     }
 16 destroyMsgQueue(msgid);
 17 return 0;
 18 }

猜你喜欢

转载自blog.csdn.net/cx2479750196/article/details/80409562