您的位置:首页 > 编程语言

使用消息队列进行进程间通信(代码实例)

2017-12-02 19:20 435 查看
使用消息队列进行进程间通信(代码实例)
 
v 消息队列间的通信方式

1.消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。
 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。也就是你先要接收那个进程的消息,你就要知道这个消息的类型。

2.那么这个数据块到底是专门定义的呢?我们又是否可以自己定义呢?
其实,Linux下的man手册里面就给出了定义.使用命令:man
 2  magsnd (man手册第二章)即可查阅。
以下是定义:(自己也可以定义,注意好数据类型即可)
struct msgbuf
{
       long mtype;     /* message type, must be > 0 */
       char mtext[1];  /* message data */
    };

举例来讲:有3个进程,2
个进程A和B用来发送消息,mtype分别为
mtype = 1和mtype = 2,另外一个进程用来接收消息。如果你想要接收A的消息,你的接收消息的函数里面就要填写mtype
= 1,以代表你想要接收A的消息。

3.消息队列的优缺点
利用消息队列,我们可以通过来避免命名管道的同步和阻塞问题。
但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
 
v 消息队列中的接口函数

1.ftok函数:主要将文件路径和文件描述符转换为一个键值key(也可以自己定义一个键值,只要和其他不冲突就好)
2.msgget函数:用于创建消息队列
3.msgsnd函数:用于发送消息
4.msgrcv函数:用于接收消息

总结:接口函数其实也只有3个,一个创建,一个发送,一个接收.虽然比较少,但是要理解各个参数的含义.具体函数类型就不列下来了,大部分我们man以下即可...
下面我也会贴出例子,利用一个实例程序来学习一个新的知识点,往往容易理解的.

v      消息队列互发消息代码实例
MsgQueue3.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>

//键值
#define KEY 1234

struct msgbuf
{
long mtype;  //消息类型
char mbuf[100]; //消息内容
};

int main()
{
int ret,msgid;
struct msgbuf buf;
pid_t pid;

//创建一个消息队列
//IPC_CREAT :创建一个消息队列  IPC_EXCL :如果已经存在则报错
msgid = msgget(KEY,IPC_CREAT | IPC_EXCL);
if(-1 == ret)
{
perror("msgget");
exit(1);
}

//创建一个子进程,父进程负责发消息,子进程负责受消息
pid  = fork();
if(pid < 0)
{
perror("fork");
exit(2);
}
else if(0 == pid)
{
/*子进程不停的发消息,直到发送byebye消息,则把这个byebye发给它本身的
父进程,此时父进程发送SIGKILL信号杀掉子进程,父进程也退出循环 */

while(1)
{
//消息队列结构体获取
//注意:此时发送消息的mtype = 1 (即发送的消息在MsgQueue4.c的父进程可以接收得到)
scanf("%s",buf.mbuf);
buf.mtype = 1;

//发送消息
ret = msgsnd(msgid,&buf, sizeof(buf.mbuf),0);
if(-1 == ret)
{

perror("msgsnd");
exit(2);
}

//若是byebye,则发送信号给其本身的父进程,而本身能接收到的mtype = 2
//注意:注意与上面的mtype = 1区分
if(!strncmp(buf.mbuf,"byebye",6))
{
buf.mtype = 2;
ret = msgsnd(msgid,&buf, sizeof(buf.mbuf),0);
break;
}

memset(buf.mbuf,0,sizeof(buf.mbuf));
}
}
else
{
/*父进程不停的读消息,直到接收到byebye消息,就发送SIGKILL信号杀掉子进程,父进程也退出循环 */
while(1)
{
//读之前清空结构体
memset(buf.mbuf,0,sizeof(buf.mbuf));

//接收mtype = 2的消息
ret = msgrcv(msgid,&buf, sizeof(buf.mbuf),2,0);
if(-1 == ret)
{
perror("msgrcv");
exit(3);
}

//打印出消息
printf("Read from msgid = 2:%s \n",buf.mbuf);

//接收到byebye后,杀掉子进程
if(!strncmp(buf.mbuf,"byebye",6))
{
kill(pid,SIGKILL);
break;
}
}

waitpid(pid,NULL,0);   //确保父进程后退出
}

//若没有这句话,需要用命令删掉消息队列的msgid
msgctl(msgid,IPC_RMID,NULL);  //删除msgid

return 0;
}


MsgQueue4.c

//MsgQueue4.c大致与MsgQueue3.c相同,将相应的mtype改掉即可

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>

#define KEY 1234

struct msgbuf
{
long mtype;
char mbuf[100];
};

int main()
{
int ret,msgid;
struct msgbuf buf;
pid_t pid;

msgid = msgget(KEY,0);
if(-1 == ret)
{
perror("msgget");
exit(1);
}

pid  = fork();
if(pid < 0)
{
perror("fork");
exit(2);
}
else if(0 == pid)
{
while(1)
{
//写
scanf("%s",buf.mbuf);
buf.mtype = 2;

ret = msgsnd(msgid,&buf, sizeof(buf.mbuf),0);
if(-1 == ret)
{

perror("msgsnd");
exit(2);
}

if(!strncmp(buf.mbuf,"byebye",6))
{
buf.mtype = 1;
ret = msgsnd(msgid,&buf, sizeof(buf.mbuf),0);
break;
}

memset(buf.mbuf,0,sizeof(buf.mbuf));
}
}
else
{
while(1)
{
memset(buf.mbuf,0,sizeof(buf.mbuf));

ret = msgrcv(msgid,&buf, sizeof(buf.mbuf),1,0);
if(-1 == ret)
{
perror("msgrcv");
exit(3);
}

printf("Read from msgid = 1:%s \n",buf.mbuf);

if(!strncmp(buf.mbuf,"byebye",6))
{
kill(pid,SIGKILL);
break;
}
}
}

msgctl(msgid,IPC_RMID,NULL);  //删除msgid

return 0;
}


v 消息队列互发消息示意图



Ps:昨天看见老师用画图画的挺好的,今天自己也画了一幅示意图。果然,按住shift画出来的线是直的......

其实,队列想要实现互发消息,也还是需要四个进程的.设置好你的mtype,你就可以和消息队列里面其他进程通信了.

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息