linux IPC 通信 study 四:SYSTEM_V消息队列

linux 消息队列 分为两个标准,分别为SystemV消息队列,POSIX消息队列
SystemV消息队列
几个API的解释
1,ftok
sys/ipc.h
key_t ftok(const char *path, int id);
该函数根据制定的路径和id,产生一个Key给msgq,sem,shm使用,path必须是一个可以访问的文件名,id只有低8位有用,但是id到底能不能等0,这个有疑问,从使用上来讲,可以等0,但是看手册里的解释,是个非零值.
在使用该函数的过程中要确保path不能被删除然后再重新创建,这回导致key值变化,产生意想不到的结果,其实也可以约定好一个整数值作为key。 
http://blog.csdn.net/u013485792/article/details/50764224
链接中的解释更详细一点。
 
2,msgget
sys/msg.h
int msgget(key_t key, int flag);
创建或者打开一个已经存在的消息队列,成功时返回msgid,失败是-1,errno可以判断失败的原因。
参数key:IPC_PRIVATE,创建一个只能被创建进程读写的消息队列,
可以是一个约定好的数值
可以使用ftok获得。
参数flag: IPC_CREAT如果消息队列存在就返回,如果不存在就创建一个新的。
IPC_EXCL如果消息队列存在,就出错,如果不存在就正常创建,这样可以保证产生的是一个新的消息队列。

消息的定义
struct mymsg {
long mtype; /*消息类型positive message type*/
char mtext[1];/*message data, of length nbytes,真正的消息长度,nbytes参数的值*/
};
3,msgsnd
向消息队列中发送一个消息
sys/msg.h
int msgsnd(int msgid, const void *ptr, size_t nbytes, int flag);
成功返回0,失败返回-1,errno标识错误类型
参数msgid是msgget的返回值。
参数ptr指向消息的指针。
参数nbytes是实际的消息长度,并不包括mtype的长度。
参数flag, IPC_NOWAIT表示以非阻塞的方式发送消息,如果消息队列已经满了,立即出错返回EAGAIN,如果不制定就会阻塞在这里直到消息成功发送
4,msgrcv
从消息队列中取出消息
sys/msg.h
size_t msgrcv(int msgid, void *ptr, size_t nbytes, long type, int flag);
函数执行成功,返回消息数据部分的长度,若出错返回-1
参数msgid是通过msgget获得的。
参数ptr指向存储读出来消息的存储空间
参数nbytes标识消息部分的长度,不包括mtype的长度
参数type表示想要哪一种消息,0表示返回队列中的第一个消息, 正数,表示返回正数类型的消息的第一个消息,负数,表示返回消息类型小于等于abs(type)的消息,如果这种消息有若干个,则取消息类型最小的那个。
参数flag, IPC_NOWAIT同样表示阻塞非阻塞
5,msgctl
对消息队列进行处理,类似于ioctl函数
sys/msg.h
int msgctl(int msgid, int cmd, struct msgid_ds *buf);
成功返回0,失败返回-1, errno指示错误类型
参数msgid是通过msgget获得的
参数cmd: IPC_STAT获取消息队列的msgid_ds结构
IPC_SET 设置相关信息
IPC_RMID 删除消息队列,注意system v并没有msgclose这样的函数

提供一个会话程序
server部分
/*************************************************************************
    > File Name: svr.c
    > Author: ma6174
    > Mail: ma6174@163.com 
    > Created Time: 2016年12月23日 星期五 13时55分00秒
 ************************************************************************/

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

#define MSGQ "/"
#define MSGQ_RES "/home"
#define MSG_SIZE 512
struct mymsg {
	long mtype;
	unsigned char msg_buf[MSG_SIZE];
};

int server_msgsnd(int msgq, void *data, int size, int flag)
{
	int ret = 0;
	while (1) {
		ret = msgsnd(msgq, data, size, flag);
		if (ret >= 0)
			return ret;
		else {
			/*
			printf("server send msg :%s\n", strerror(errno));
			if (errno == ENOMSG || errno == EAGAIN) {
				if (errno == ENOMSG)
					printf("server send : NO MSG \n");
				if (errno == EAGAIN)
					printf("server send : MSG AGAIN\n");
			}
			sleep(1);
			continue;
			*/
		}
	}
	return ret;
}

int server_msgrcv(int msgq, void *data, int size, int request, int flag)
{
	int ret = 0;
	while (1) {
		ret = msgrcv(msgq, data, size, request, flag);
		if (ret >= 0) {
			return ret;
		} else {
			if (errno == EIDRM) {
				printf("server:msg queue was rm by client\n");
				exit(1);
			}

			/*
			printf("server send msg %s\n", strerror(errno));
			if (errno == ENOMSG || errno == EAGAIN) {
				if (errno == ENOMSG)
					printf("server recv : NO MSG \n");
				if (errno == EAGAIN)
					printf("server recv : MSG AGAIN\n");
			}
			sleep(1);
			continue;
			*/

		}
	}
	return ret;
}

int main(int argc, char **argv)
{
	/* 
	 * 1 ftok get key or use a fixed num
	 * 2 msgget open or create a message queue
	 * 3 msgsnd msgrcv send or receive info
	 * 4 msgctl close message queue
	 * */

	key_t key;
	int ret = 0;
	int proj_id = 0x01;
	key = ftok(MSGQ, proj_id);

	int msgq = msgget(key, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO);
	if (msgq < 0) {
		printf("create msg queue failed\n");
		return -1;
	}

	int msgq_res = msgget(0x25, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO);

	struct mymsg rcv_msg_data, snd_msg_data;
	while (1) {

		memset(&rcv_msg_data, 0, sizeof(struct mymsg));
		memset(&snd_msg_data, 0, sizeof(struct mymsg));

		//ret = server_msgrcv(msgq, &rcv_msg_data, sizeof(struct mymsg), 0, IPC_NOWAIT);
		ret = server_msgrcv(msgq, &rcv_msg_data, MSG_SIZE, 0, IPC_NOWAIT);
		if (ret >= 0) {
			printf("server recv msg ok len = %d\n", ret);
		} else {
			if (errno == EIDRM) {
				printf("server:msg queue was rm by client\n");
				exit(1);
			}
		}

		if (rcv_msg_data.mtype == 1) {
			snd_msg_data.mtype = rcv_msg_data.mtype;
			printf("server: msg request 1\n");
			strcpy(snd_msg_data.msg_buf, "you request msg type 1");
		} else if (rcv_msg_data.mtype == 2) {
			snd_msg_data.mtype = rcv_msg_data.mtype;
			printf("server: msg request 2\n");
			strcpy(snd_msg_data.msg_buf, "you request msg type 2");
		} else if (rcv_msg_data.mtype == 3) {
			snd_msg_data.mtype = rcv_msg_data.mtype;
			printf("server: msg request 3\n");
			strcpy(snd_msg_data.msg_buf, "you request msg type 3");
		}

		//ret = server_msgsnd(msgq, &snd_msg_data, sizeof(struct mymsg), IPC_NOWAIT);
		ret = server_msgsnd(msgq_res, &snd_msg_data, MSG_SIZE, IPC_NOWAIT);
		if (ret >= 0) {
			printf("server send msg ok len = %d\n", ret);
		} else {
			printf("server: send msg failed\n");
		}

		usleep(10);
	}
	return ret;
}

client部分
/*************************************************************************
    > File Name: svr.c
    > Author: ma6174
    > Mail: ma6174@163.com 
    > Created Time: 2016年12月23日 星期五 13时55分00秒
 ************************************************************************/

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

#define MSGQ "/"
#define MSG_SIZE (512)

struct mymsg {
	long mtype;
	unsigned char msg_buf[512];
};

int client_send(int msgq, void *data, int size, int flag)
{
	int ret = 0;
	while (1) {
		ret = msgsnd(msgq, data, size, flag);
		if (0 == ret)
			return ret;
		else if (ret < 0) {
			/*
			if (errno == ENOMSG || errno == EAGAIN) {
				if (errno == ENOMSG)
					printf("client send:NO MSG \n");
				if (errno == EAGAIN)
					printf("client send: MSG AGAIN\n");
			}
			*/
			continue;
		}
	}
	return ret;
}

int client_msgrcv(int msgq, void *data, int size, int request, int flag)
{
	int ret = 0;
	while (1) {
		ret = msgrcv(msgq, data, size, request, flag);
		if (ret >= 0)
			return ret;
		if (ret < 0) {
			/*
			if (errno == ENOMSG || errno == EAGAIN) {
				if (errno == ENOMSG)
					printf("client recv : NO MSG \n");
				if (errno == EAGAIN)
					printf("client recv : MSG AGAIN\n");
			}
			*/
			continue;
		}
	}
	return ret;

}
int main(int argc, char **argv)
{
	int ret = 0;
	key_t key;
	int proj_id = 0x01;
	key = ftok(MSGQ, proj_id);

	int msgq = msgget(key, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO);
	if (msgq < 0) {
		printf("create msg queue failed\n");
		return -1;
	}
	int msgq_res = msgget(0x25, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO);

	struct mymsg rcv_msg_data, snd_msg_data;
	int idx = 1;
	while (idx < 4) {

		memset(&rcv_msg_data, 0, sizeof(struct mymsg));
		memset(&snd_msg_data, 0, sizeof(struct mymsg));

		snd_msg_data.mtype = idx;
		//ret = client_send(msgq, &snd_msg_data, sizeof(struct mymsg), IPC_NOWAIT);
		ret = client_send(msgq, &snd_msg_data, MSG_SIZE, IPC_NOWAIT);
		if (ret < 0)
			printf("client send msg fail\n");
		else if (0 == ret)
			printf("\tclient send type %d\n", idx);


		ret = client_msgrcv(msgq_res, &rcv_msg_data, MSG_SIZE,
				rcv_msg_data.mtype, IPC_NOWAIT);
		if (ret < 0) {
			printf("\tclient receive msg failed\n");
		} else 
			printf("\t\tclient get : len = %d, type = %ld, %s\n", ret, rcv_msg_data.mtype, rcv_msg_data.msg_buf);
		idx++;
		usleep(50);
	}
	sleep(10);
	/*client close msg queue, in fact, client cannot remove msgq*/
	ret = msgctl(msgq, IPC_RMID, NULL);
	ret = msgctl(msgq_res, IPC_RMID, NULL);
	printf("client exit and rm msg queue\n");
	return ret;
}

执行效果如图:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值