进程间通信-队列



消息队列
消息队列是通过标识来引用,消息队列类似于一个消息链表,通过队列标识来引用,标识通过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;
	/*============================================*/
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值