消息队列
消息队列是通过标识来引用,消息队列类似于一个消息链表,通过队列标识来引用,标识通过key来获取msgget(key_t key, int flag)。
创建队列过程:
1.确定队列的key,key可以自定义,也可以利用ftok来获取一个key
①利用ftok来得到一个key值ftok(const char * path, int id)路径必须是一个存在的文件路径,否则一直阻塞在那里id取值范围0-255
②key自定义,然后把key值放在公共头文件里,方便包含该头文件的其他文件使用
③key自定义,然后把key放在一个文件中,不同进程都可以通过访问该文件来访问这个key
2.通过key来创建消息队列并获取队列标识
3.向队列发送数据msgsnd或读取数据msgrcv来进行通信
读取消息队列中的数据是先进先出或者按照设置的读取的数据类型来随机读取
创建消息队列的进程结束,但是消息队列以及队列中的数据还是依然存在,除非显示的删除:
1.由其他进程读或者删除消息队列
2.由系统删除
函数msgget
msgget - get a message queue identifier
获取消息队列标识
函数概述
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
返回与key相关的队列的标识,如果key的值为IPC_PRIVATE或者key的值不等于其他已存在的队列的key,而且msgflg指定了IPC_CREAT,则创建一个新的队列
如果msgflg设置为IPC_CREAT|IPC_EXCL,则如果对应的key已经存在于已存在的队列,则创建失败,errno为EEXIST。
在创建队列的时候,参数msgflg最低有效位是定义队列权限的,这些权限位和open的参数mode用法一样除可执行权限不能用
如果一个队列被创建,那么与它相关的结构msqid_ds 会被初始化:
msg_perm.cuid and msg_perm.uid会被设置成引用队列的进程的用户id
msg_perm.cgid and msg_perm.gid会被设置成引用队列的进程的组id
msg_perm.mode低9位与msgflg的低9位对应
msg_qnum, msg_lspid, msg_lrpid, msg_stime and msg_rtime初始化为0
msg_ctime 设为当前时间
msg_qbytes 会初始化为系统限制队列的最大字节数
如果要创建的队列已经存在而且具有读写权限,则检查是否成功可以查看返回值
成功返回队列的id(非负数),失败返回-1
失败则会设置errno,值描述如下:
EACCES 参数key对应的队列已经存在,且调用进程对队列没有权限,也没有CAP_IPC_OWNER(绕过检查系统对对象的权限)
EEXIST 参数key对应的队列已经存在,而且msgflg设置为 IPC_CREAT and IPC_EXCL
ENOMEM 一个新的队列会被创建,但是系统没有更多的内存了
ENOSPC 超过了系统允许创建的队列中最大存储数据(65536)
注意
1.IPC_PRIVATE 类型是key_t,不是一个标志字段,当用于参数key调用时,系统会忽略其他参数除msgflg的低9位的权限位,关于megget调用相关联的系统限制:MSGMNI 系统允许的队列最大个数,与系统相关(linux 限制值可通过/proc/sys/kernel/msgmni修改或获取 31683)
2.在linux2.3.20版本以前,当调用msgget()而队列已被删除时会返回EIDRM
3.创建队列时使用IPC_PRIVATE会有很多不确定因素,建议使用IPC_NEW
#define FUN1_ID 10001
#define FUN2_ID 10002
#define usr_path "/usr/test/ok/test"
#define usr_id 109870
typedef struct _ipc_data_info_
{
long s_type;
char s_data[70000];
}ipc_data_info;
int ipc_msg_fun1(pid_t a_id)
{
key_t b_msg_key;
int b_msg_id;
int b_ret, b_loop, b_id;
char b_tmp_buf[1024] = {0};
char * b_tmp_ptr = (char *)malloc(65530);
ipc_data_info b_ipc_snd = {0}, b_ipc_rcv = {0};
struct msqid_ds b_ipc_buf = {0};
//msgctl();
//b_msg_key = ftok(usr_path, usr_id);
b_msg_key = ftok(usr_path, usr_id);
if(b_msg_key < 0)
{
printf("ftok fail %d, line = %d, fun = %s, file = %s\n", \
b_msg_key, __LINE__, __func__, __LINE__);
return -1;
}
b_msg_id = msgget(b_msg_key, IPC_CREAT|0666);
if(b_msg_id < 0)
{
printf("msgget fail %d, line = %d, fun = %s, file = %s\n", \
b_msg_id, __LINE__, __func__, __LINE__);
return -1;
}
memset(&b_ipc_buf, 0, sizeof(b_ipc_buf));
msgctl(b_msg_id, IPC_STAT, &b_ipc_buf);
printf("id = %d, key = %d, limit = %d\n", b_msg_id, b_msg_key, b_ipc_buf.msg_qbytes);
//msgctl(b_msg_id, IPC_RMID, &b_ipc_buf);
b_ipc_snd.s_type = FUN1_ID;
b_ipc_rcv.s_type = FUN2_ID;
b_loop = 0;
while(1)
{
memset(b_tmp_ptr, 0, sizeof(b_tmp_ptr));
sprintf(b_tmp_ptr, "test_data %d", b_loop);
memset(b_ipc_snd.s_data, 0, sizeof(b_ipc_snd.s_data));
memcpy(b_ipc_snd.s_data, b_tmp_ptr, strlen(b_tmp_ptr));
b_ret = msgsnd(b_msg_id, &b_ipc_snd, 1024, 0);
if(b_ret < -1)
{
printf("msgsnd fail %d, line = %d, fun = %s, file = %s\n", b_ret, __LINE__, __func__, __FILE__);
return -1;
}
printf("send data success data = %s\n", b_ipc_snd.s_data);
#if 0
b_ret = msgrcv(b_msg_id, &b_ipc_rcv, 1024, b_ipc_rcv.s_type, 0);
if(b_ret < -1)
{
printf("msgsnd fail %d, line = %d, fun = %s, file = %s\n", b_ret, __LINE__, __func__, __FILE__);
return -1;
}
printf("recv data = %s\n", b_ipc_rcv.s_data);
#endif
b_loop++;
if(b_loop > 10000)
{
b_loop = 0;
}
sleep(2);
}
return 0;
}
int ipc_msg_fun2(pid_t a_id)
{
key_t b_msg_key;
int b_msg_id;
int b_ret, b_loop;
char b_tmp_buf[1024] = {0};
ipc_data_info b_ipc_snd = {0}, b_ipc_rcv = {0};
b_msg_key = ftok(usr_path, usr_id);
if(b_msg_key < 0)
{
printf("ftok fail %d, line = %d, fun = %s, file = %s\n", \
b_msg_key, __LINE__, __func__, __LINE__);
return -1;
}
b_msg_id = msgget(b_msg_key, IPC_CREAT|0666);
if(b_msg_id < 0)
{
printf("msgget fail %d, line = %d, fun = %s, file = %s\n", \
b_msg_id, __LINE__, __func__, __LINE__);
return -1;
}
b_ipc_snd.s_type = FUN2_ID;
b_ipc_rcv.s_type = FUN1_ID;
b_loop = 0;
while(1)
{
#if 0
memset(b_tmp_buf, 0, sizeof(b_tmp_buf));
sprintf(b_tmp_buf, "test_data1 %d", b_loop);
memset(b_ipc_snd.s_data, 0, sizeof(b_ipc_snd.s_data));
memcpy(b_ipc_snd.s_data, b_tmp_buf, strlen(b_tmp_buf));
b_ret = msgsnd(b_msg_id, &b_ipc_snd, strlen(b_ipc_snd.s_data), 0);
if(b_ret < -1)
{
printf("msgsnd fail %d, line = %d, fun = %s, file = %s\n", b_ret, __LINE__, __func__, __FILE__);
return -1;
}
printf("send data success\n");
#endif
memset(&b_ipc_rcv, 0, sizeof(b_ipc_rcv));
b_ret = msgrcv(b_msg_id, &b_ipc_rcv, 1024, b_ipc_rcv.s_type, 0);
if(b_ret < -1)
{
printf("msgsnd fail %d, line = %d, fun = %s, file = %s\n", b_ret, __LINE__, __func__, __FILE__);
return -1;
}
printf("recv data = %s\n", b_ipc_rcv.s_data);
#if 0
b_loop++;
if(b_loop > 10000)
{
b_loop = 0;
}
#endif
sleep(1);
}
return 0;
}
int main()
{
/*============================================*/
/*队列*/
int b_loop = 0, b_ret;
pid_t b_id[10];
b_id[b_loop] = fork();
if(b_id[b_loop] < 0)
{
printf("fork fail %d, line = %d, fun = %s, file = %s\n", b_id, __LINE__, __func__, __FILE__);
return -1;
}
else if(0 == b_id[b_loop])
{
/*子进程*/
ipc_msg_fun1(b_id[b_loop]);
}
b_loop++;
b_id[b_loop] = fork();
if(b_id[b_loop] < 0)
{
printf("fork fail %d, line = %d, fun = %s, file = %s\n", b_id, __LINE__, __func__, __FILE__);
return -1;
}
else if(0 == b_id[b_loop])
{
/*子进程*/
ipc_msg_fun2(b_id[b_loop]);
}
b_loop++;
while(1)
{
b_ret = wait(NULL);
if(b_ret < -1)
{
printf("son process over %d, line = %d, fun = %s, file = %s\n", b_ret, __LINE__, __func__, __FILE__);
break;
}
}
return 0;
/*============================================*/
}