进程间通信——消息队列

上一次我们看的管道是单向通信,如果你想用管道进行双向通信,可以创建两个管道。下面我们再来看一个可以双向通信的——消息队列(msgqueue)

消息队列提供了一种从一个进程向另一个进程发送一个有类型数据块的方法。

创建消息队列用的函数是:

int msgget(key_t key, int msgflg);

其中,key(消息队列标识符)可以看成端口号,管道用的是文件描述符来判断确定父子进程使用的是同一个管道,这里的key也是相同的功能,key可以用ftok()函数生成,那么我们在来看一下ftok()函数

key_t ftok(const char* pathname, int proj_id)
//成功返回消息队列标识符,失败返回-1

第二个参数:msgflag一般为:IPC_CREAT、IPC_EXCL

前一个是如果不存在,则创建,存在,则打开;后一个单独使用没有什么意义;两个一起使用的意思是:

能创建就能删除,删除用的函数是:

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

这个不仅仅可以用来删除,还可以进行其他的操作,是控制消息队列的函数。其中第一个参数就是要删除的消息队列的ID,第二个参数是IPC_RMID,第三个参数不需要关心,直接设置为空就可。删除成功返回0,失败返回-1.

下面是实现消息队列的代码:

//comm.h
  1 #ifndef _COMM_H_
  2 #define _COMM_H_
  3 
  4 #include<stdio.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 #include<sys/msg.h>
  8 #include<sys/ipc.h>
  9 #include<stdlib.h>
 10 #include<string.h>
 11 
 12 #define PATHNAME "."
 13 #define ID 0x6666
 14 
 15 #define SERVER_TYPE 1
 16 #define CLIENT_TYPE 2
 17 
 18 struct msgbuf
 19 {
 20     long mtype;
 21     char mtext[1024];
 22 };
 23 
 24 int creatMsgQueue();
 25 int getMsgQueue();
 26 int destroyMsgQueue(int msgid);
 27 int sendMsg(int msgid,int type,const char* msg);
 28 int recvMsg(int msgid,int type,char* out);
 29 
 30 
 31 #endif
//comm.c
  1 #include"comm.h"
  2 
  3 static int commMsgQueue(int flags)
  4 {
  5     key_t _key=ftok(PATHNAME,ID);//get key
  6     if(_key<0)
  7     {
  8         perror("ftok");
  9         return -1;
 10     }
 11     int msgid=msgget(_key,flags);
 12     if(msgid<0)
 13     {
 14         perror("msgget");
 15         return -2;
 16     }
 17     return msgid;
 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 destroyMSgQueue(int msgid)
 31 {
 32     if(msgctl(msgid,IPC_RMID,NULL)<0)
 33     {
 34         perror("msgctl");
 35         return -3;
 36     }
 37     return 0;
 38 }
 39 
 40 int sendMsg(int msgid,int type,const char* msg)
 41 {
 42     struct msgbuf _mb;
 43     _mb.mtype=type;
 44     strcpy(_mb.mtext,msg);
 45     if(msgsnd(msgid,&_mb,sizeof(_mb.mtext),0)<0)
 46     {
 47         perror("msgsnd");
 48         return -4;
 49     }
 50     return 0;
 51 }
 52 
 53 int recvMsg(int msgid,int type,char *out)
 54 {
 55     struct msgbuf _mb;
 56     if(msgrcv(msgid,&_mb,sizeof(_mb.mtext),type,0)<0)
 57     {
 58         perror("msgrcv");
 59         return -5;
 60     }
 61     strcpy(out,_mb.mtext);
 62     return 0;
 63 }
 64 
  1 #include"comm.h"
  2 
  3 int main()
  4 {
  5     int msgid = creatMsgQueue();
  6     char buf[1024];
  7     while(1)
  8     {
  9         buf[0]=0;
 10         recvMsg(msgid,CLIENT_TYPE,buf);
 11         printf("client say: %s\n",buf);
 12         printf("Please Enter:");
 13         fflush(stdout);
 14         ssize_t s=read(0,buf,sizeof(buf)-1);
 15         if(s>0)
 16         {
 17             buf[s-1]=0;//no '\n'
 18             sendMsg(msgid,SERVER_TYPE,buf);
 19         }
 20     }
 21 //  detoryMsgQueue(msgid);
 22 
 23     return 0;
 24 }
  1 #include"comm.h"
  2 
  3 int main()
  4 {
  5     int msgid=getMsgQueue();
  6     char buf[1024];
  7     while(1)
  8     {
  9         buf[0]=0;
 10         printf("Please Enter: ");
 11         fflush(stdout);
 12         ssize_t s=read(0,buf,sizeof(buf)-1);
 13         if(s>0)
 14         {
 15             buf[s-1]=0;
 16             sendMsg(msgid,CLIENT_TYPE,buf);
 17         }
 18         recvMsg(msgid,SERVER_TYPE,buf);
 19         printf("server say: %s\n",buf);
 20     }
 21     return 0;
 22 }

消息队列的特性,除了上面我们说的,它是双向的,还有一个比较重要的特性,就是,它随内核:如果进程退出,不用指令或系统调用删除消息队列,除非关机或重启,那么消息队列一直存在。

对了,如果你在运行过程中出现问题,那么重新调试过后,会发现还是有问题,这时候,你需要将你原来的消息队列删除,再创建一个新的来。查看和删除消息队列的命令就很重要了:

iccs -q            //查看消息队列
ipcrm -q           //删除消息队列
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值