Linux-消息队列

消息队列是进程间通信System V版本(消息队列、信号量、共享内存)之一。

所谓System V版本就是其生命周期随内核(及时进程结束,消息队列也不会被删除),这是与管道的不同。

还有一个不同点就是:管道是以数据流方式来发送(接受)数据,而消息队列是以数据块的方式来发送(接受)数据。

首先,下面是有关消息队列的系统调用:

1、int msgget(key_t key, int msgflg);  //成功返回消息队列的编号,失败返回-1

    作用:

    用来创建或者获取一个消息队列

    头文件:

    #include <sys/types.h>

    #include <sys/ipc.h>

    #incldue <sys/msg.h>

   参数:

    第一个参数是一个唯一的key值。其一般由ftok函数生成。

    key_t ftok(const char* pathname, int proj_id);   //成功返回0,失败返回-1.

        第一个参数一般使用当前文件的路径或文件名,第二个参数一般给一个整数(其实,随意给一个就可以,ftok内部会通过这两个参数经过某种运算生成一个唯一的key值来标识该消息队列)

    第二个参数为一般为:IPC_CREAT和IPC_EXCL组合或单独使用,如要使用多个,只需要用“|”(或)链接起来。

        1>、IPC_CREAT:如果消息队列不存在,则创建之,并返回消息队列的编号,如果存在,则返回当前现有的消息队列编号。

        2>、IPC_CREAT|IPC_EXCL:如果消息队列存在则出错返回,否则创建之。(意味着,一定可以保证创建一个新的消息队列)

        3>、IPC_EXCL:该选项一般不单独使用,单独使用没有任何意义。

        4>、IPC_CREAT|IPC_EXCL|0666 在2的基础上可以设置该消息队列的权限为0666。

2、int msgctl(int msgid,int cmd,struct msgid_ds *buf); //失败返回-1,成功返回0(IPC_STAT/IPC_SET/IPC_RMID)

    作用:

    用来对消息队列执行一些操作(包括删除操作)

    参数:

    第一个参数为消息队列的编号msgid;

    第二个参数为属性,用来告诉操作系统要执行什么操作,比如(IPC_RMID删除、IPC_STAT查看消息信息)

    第三个参数为辅助参数。

        IPC_RMID:可以将该参数设置为NULL,因为不关心该结构体的信息(消息队列用一个叫msgid_ds的结构体来描述)。

        IPC_STAT:该参数为一个输出型参数,来获取msgid_ds这个结构体。

3、int msgsnd(int msgid, const void* ptr,size_t bytes,int flag);//成功返回0,失败返回-1

    作用:

    向消息队列发送数据。

    参数:

    第一个参数为消息队列的id;

    第二个参数为要发送的数据内容,需要用到一个结构体(struct msgbuf)来发送数据;(需要以块为单位发送数据)

    第三个参数为要发送数据的大小(以字节为单位);

    第四个参数为标志位,代表该消息以什么方式来发送。当其值为0时,代表以阻塞方式发送数据。

4、ssize_t msgrcv(int msgid, void* ptr,size_t bytes,long msgtype,int flag);

    作用:

    接受消息。

    参数:

    很明显的可以看到,比msgsnd多了一个参数,就是long msgtype,为什么要多这个参数呢?

    其实,大家想想也很简单,既然是以数据块的方式发送数据,那么也应该要以数据块的方式接受,而这个就是表示你要收的数据是那个类型的。就像你买东西的时候,先要知道要买什么东西。

5、struct msgbuf

     {

         long mtype;  

         char mtext[1];

    }

    首先要声明的是:该结构体需要自己定义。

    第一个成员就是我们上边说的msgtype,标明该被发送(接受)的数据是什么类型(这里的类型不是变量的类型,是给数据块自定义一个名字)。

    第二个成员是一个字符数组,大小在定义的时候可以自行设定。

   

好!那么接下来就演示一下,如何使用消息队列来完成进程间的通信。

首先要得知道,如何使用Linux命令查询当前的消息队列。

    ipcs -q 查看消息队列(如果在普通用户下查看不到,切换到root下就可以看到)。

    ipcrm -q msqid号 删除该消息队列。

代码:共有4个文件:comm.h、comm.c、server.c、client.c

1、comm.h

#ifndef  __COMM_H__
#define __COMM_H__

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

#define MAX_TEXT 1024   //自定义发送数据的最大大小为1024字节

#define SERVER 1
#define CILENT 2

struct msgbuf
{
	long mtype;
	char mtext[MAX_TEXT];
};
//对系统调用进行封装
int CreatMsgQueue();

int GetMsgQueue();

int SendMsg();

int RcvMsg();

int DestoryMsgQueue();




#endif // __COMM_H__

2、comm.c

#include "comm.h"



int CommMsgQueue(int flgs)
{
	
	key_t key = ftok("./comm.h",0);	

	int msgid = 0;

	if((msgid = msgget(key,flgs)) == -1)
	{
		perror("msgget");
		return -1;
	}

	return msgid;
}

int CreatMsgQueue()
{
	return CommMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}

int GetMsgQueue()
{
	return CommMsgQueue(IPC_CREAT);
}

int SendMsg(int msgid,char* data,int name)
{	
	struct msgbuf mb;
	
	mb.mtype = name;
	strcpy(mb.mtext, data);

	if(msgsnd(msgid,&mb,MAX_TEXT,0) == -1)
	{
		perror("msgsnd");
		return -1;
	}
	
	return 0;
}

int RcvMsg(int msgid,int name,struct msgbuf* buf)
{
	if(msgrcv(msgid,buf,MAX_TEXT,name,0)==-1)
	{
		perror("msgrcv");
		return -1;
	}

	return 0;
}

int DestoryMsgQueue(int msgid)
{
	if(msgctl(msgid,IPC_RMID,NULL) == -1)
	{
		perror("msgctl");
		return -1;
	}

	return 0;
}


3、server.c

#include "comm.h"

//server.c

int main()
{
	int msgid = CreatMsgQueue();
	
	while(1)
	{
		char msg[MAX_TEXT];
		printf("server:");
		fflush(stdout);
		int s = read(0,msg,sizeof(msg));
		if(s<0)
		{
			perror("read");
			return 1;
		}
		msg[s-1]=0;
		
		SendMsg(msgid,msg,SERVER);
		

		struct msgbuf buf;
		RcvMsg(msgid,CILENT,&buf);

		printf("cilent:%s\n",buf.mtext);
	}


	DestoryMsgQueue(msgid);

	return 0;
}

4、client.c

#include "comm.h"

//client.c

int main()
{
	int msgid = GetMsgQueue();	
	while(1)
	{
		struct msgbuf buf;
		RcvMsg(msgid,SERVER,&buf);
		printf("server:%s\n",buf.mtext);

		char msg[MAX_TEXT];
		printf("cilent:");
		fflush(stdout);
		int s = read(0,msg,sizeof(msg));
		if(s<0)
		{
			perror("read");
			return 1;
		}
		msg[s-1]=0;
		
		SendMsg(msgid,msg,CILENT);
	}

	return 0;
}

5、运行结果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值