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

来源:互联网 发布:桌面录制视频软件 编辑:程序博客网 时间:2024/05/18 14:46
linux 消息队列 分为两个标准,分别为SystemV消息队列,POSIX消息队列
SystemV消息队列几个API的解释1,ftoksys/ipc.hkey_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 512struct 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;}

执行效果如图:





0 0
原创粉丝点击