您的位置:首页 > 运维架构 > Linux

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

2015-11-03 17:45 567 查看
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(i
4000
nt 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;
}

执行效果如图:

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